{"record":{"id":"2160a45e2fa34de3","repo":"theonedev/onedev","slug":"tag-request-gettagname-already-exists","errorCode":null,"errorMessage":"Tag '${request.getTagName()}' already exists","messagePattern":"Tag '(.+?)' already exists","errorType":"http","errorClass":"NotAcceptableException","httpStatus":406,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/rest/resource/RepositoryResource.java","lineNumber":236,"sourceCode":"\t\tRefResponse response = new RefResponse();\n\t\t\n\t\tresponse.refName = ref.getName();\n\t\tresponse.commitHash = project.getRevCommit(ref.getObjectId(), true).getName();\n\t\t\n\t\treturn response;\n\t}\n\t\n\t@Api(order=70, description=\"Create a new tag\")\n\t@Path(\"/{projectId}/tags\")\n\t@POST\n\tpublic Response createTag(@PathParam(\"projectId\") Long projectId, @NotNull CreateTagRequest request) {\n\t\tProject project = projectService.load(projectId);\n\t\tif (!SecurityUtils.canCreateTag(project, request.getTagName())) {\n\t\t\tthrow new UnauthorizedException();\n\t\t}\n\n\t\tif (project.getTagRef(request.getTagName()) != null) {\n\t\t\tthrow new NotAcceptableException(\"Tag '\" + request.getTagName() + \"' already exists\");\n\t\t} else {\n\t\t\tUser user = SecurityUtils.getUser();\n\t\t\tgitService.createTag(project, request.getTagName(), request.getRevision(), user.asPerson(), \n\t\t\t\t\trequest.getTagMessage(), project.isTagSignatureRequired(user, request.getTagName()));\n\t\t}\n\n\t\treturn Response.ok().build();\n\t}\n\t\n\t@Api(order=80, description=\"Delete specified tag\")\n\t@Path(\"/{projectId}/tags/{tag:.*}\")\n\t@DELETE\n\tpublic Response deleteTag(\n\t\t\t@PathParam(\"projectId\") Long projectId, \n\t\t\t@PathParam(\"tag\") @Api(example=\"test-tag\") String tagName) {\n\t\tProject project = projectService.load(projectId);\n\t\tif (!SecurityUtils.canDeleteTag(project, tagName)) {\n\t\t\tthrow new UnauthorizedException();","sourceCodeStart":218,"sourceCodeEnd":254,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/rest/resource/RepositoryResource.java#L218-L254","documentation":"REST createTag checks project.getTagRef before creating and throws this conflict when a tag with the requested name already exists in the repository; permission to create that specific tag is verified first.","triggerScenarios":"Calling POST /~api/{projectId}/tags with a tagName that already resolves to an existing ref (e.g. re-running a release job for an already-cut version).","commonSituations":"Re-running a failed release pipeline that already created the tag; re-releasing the same version number; collision between automated and manual tagging.","solutions":["Use a new version/tag name","Delete the existing tag first (if permitted) then recreate it","Make automation idempotent: check GET /~api/{projectId}/tags/{tag} before POST and skip if 200","Fix version numbering scheme to avoid duplicate releases"],"exampleFix":"// before\nPOST /~api/1/tags {\"tagName\":\"v1.0\",\"revision\":\"main\"} // already exists\n// after\nPOST /~api/1/tags {\"tagName\":\"v1.0.1\",\"revision\":\"main\"}","handlingStrategy":"validation","validationCode":"let exists = false;\ntry { await api.get(`/projects/${id}/tags/${tagName}`); exists = true; } catch (e) {}\nif (exists) throw new Error(`tag ${tagName} already exists`);","typeGuard":null,"tryCatchPattern":"try {\n  createTag(projectId, req);\n} catch (NotAcceptableException e) {\n  // treat as idempotent or bump version\n}","preventionTips":["Check tag existence before creating","Make release pipelines idempotent on retry","Enforce unique version numbers in CI"],"tags":["rest","git","tags","conflict"],"backgroundTag":"file-already-exists","analyzedSha":"d44925c47c37992c828ea673a5f9620539bc3ff2","analyzedAt":"2026-09-06T07:18:27.995Z","contentChangedAt":"2026-09-06T07:18:27.995Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}