Unable to add topic to project

Everyone can contribute. Help move this issue forward while earning points, leveling up and collecting rewards.

Summary

On GitLab.com, adding the topic tier:1 or tier:2 to a project fails. The API returns 422 Unprocessable Entity with the generic body {"message":"Project could not be updated!"} and no validation details. Other topics in the same prefix:value form work, including tier:1a, tier:tier1 and foo:2. So the failure is tied to tier: followed only by digits.

The same error comes up through the Terraform GitLab provider (gitlab_project.topics), which sends the same request.

Steps to reproduce

  1. Use any project you can edit.
  2. Run:
    curl -sS -X PUT -H "PRIVATE-TOKEN: $TOKEN" -H 'Content-Type: application/json' \
      https://gitlab.com/api/v4/projects/<id> -d '{"topics":["tier:1"]}'
    

What is the current bug behavior?

  {"message":"Project could not be updated!"}

HTTP 422, with no error saying which attribute or topic failed.

Tested combinations:

Topic Result
tier:1 422
tier:2 422
tier:1a Success
tier:tier1 Success
foo:2 Success
lang:go Success
team:core Success
go Success

What is the expected correct behavior?

One of these:

  • The topic is added to the project, or
  • If the name is not allowed or clashes with an existing topic, the API returns a validation error that says so (for example topics: ... is invalid), not the generic fallback message.

Relevant logs and/or screenshots

  • Request ID: a46cd45a081279bf-LHR (2026-10-07 12:15:09 UTC), from the original failing request with topics ["lang:go","tier:1","go","team:core"]
  • GET /api/v4/topics?search=tier: output:
[{"id":1224730,"name":"Tier:∞","title":"Tier:∞","description":null,"total_projects_count":0,"organization_id":1,"avatar_url":null},{"id":3490197,"name":"tier:4","title":"tier:4","description":null,"total_projects_count":7,"organization_id":1,"avatar_url":null},{"id":3490214,"name":"tier:tier1","title":"tier:tier1","description":null,"total_projects_count":0,"organization_id":1,"avatar_url":null},{"id":3490215,"name":"tier:1a","title":"tier:1a","description":null,"total_projects_count":0,"organization_id":1,"avatar_url":null},{"id":2273671,"name":"tier:b2b","title":"tier:b2b","description":null,"total_projects_count":0,"organization_id":1,"avatar_url":null},{"id":177533,"name":"tier:core","title":"tier:core","description":null,"total_projects_count":0,"organization_id":1,"avatar_url":null},{"id":177577,"name":"tier:base","title":"tier:base","description":null,"total_projects_count":0,"organization_id":1,"avatar_url":null},{"id":177687,"name":"tier:infra","title":"tier:infra","description":null,"total_projects_count":10,"organization_id":1,"avatar_url":null},{"id":177679,"name":"tier:adapter","title":"tier:adapter","description":null,"total_projects_count":56,"organization_id":1,"avatar_url":null},{"id":177581,"name":"tier:backbone","title":"tier:backbone","description":null,"total_projects_count":70,"organization_id":1,"avatar_url":null},{"id":177685,"name":"tier:features","title":"tier:features","description":null,"total_projects_count":9,"organization_id":1,"avatar_url":null},{"id":2273672,"name":"tier:b2b-tools","title":"tier:b2b-tools","description":null,"total_projects_count":4,"organization_id":1,"avatar_url":null},{"id":177871,"name":"tier:reporting","title":"tier:reporting","description":null,"total_projects_count":14,"organization_id":1,"avatar_url":null},{"id":2275753,"name":"Service Tier: 1","title":"Service Tier: 1","description":null,"total_projects_count":7,"organization_id":1,"avatar_url":null},{"id":2275754,"name":"Service Tier: 2","title":"Service Tier: 2","description":null,"total_projects_count":18,"organization_id":1,"avatar_url":null},{"id":2275853,"name":"Service Tier: 3","title":"Service Tier: 3","description":null,"total_projects_count":14,"organization_id":1,"avatar_url":null},{"id":2275855,"name":"Service Tier: 4","title":"Service Tier: 4","description":null,"total_projects_count":2,"organization_id":1,"avatar_url":null},{"id":2279548,"name":"Service-Tier: 3","title":"Service-Tier: 3","description":null,"total_projects_count":2,"organization_id":1,"avatar_url":null},{"id":2279549,"name":"Service-Tier: 4","title":"Service-Tier: 4","description":null,"total_projects_count":6,"organization_id":1,"avatar_url":null},{"id":2279553,"name":"Service-Tier: 2","title":"Service-Tier: 2","description":null,"total_projects_count":2,"organization_id":1,"avatar_url":null}]

The message appears to come from the fallback in Projects::UpdateService#update_failed!. That fallback is used only when project.errors is empty, so the underlying failure (perhaps creating or linking the topic) is not being reported back to the caller.

Output of checks

This bug happens on GitLab.com.

Edited by 🤖 GitLab Bot 🤖