{"record":{"id":"5e8a0d9441318d02","repo":"hashicorp/nomad","slug":"tag-q-already-exists-on-a-different-version-of-jo","errorCode":null,"errorMessage":"tag %q already exists on a different version of job %q","messagePattern":"tag %q already exists on a different version of job %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/state/state_store.go","lineNumber":4935,"sourceCode":"\t}\n\n\treturn txn.Commit()\n}\n\nfunc (s *StateStore) updateJobVersionTagImpl(index uint64, namespace, jobID string, jobVersion uint64, tag *structs.JobVersionTag, txn *txn) error {\n\t// Note: could use JobByIDAndVersion to get the specific version we want here,\n\t// but then we'd have to make a second lookup to make sure we're not applying a duplicate tag name\n\tversions, err := s.JobVersionsByID(nil, namespace, jobID)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar job *structs.Job\n\n\tfor _, version := range versions {\n\t\t// Allow for a tag to be updated (new description, for example) but otherwise don't allow a same-tagname to a different version.\n\t\tif version.VersionTag != nil && version.VersionTag.Name == tag.Name && version.Version != jobVersion {\n\t\t\treturn fmt.Errorf(\"tag %q already exists on a different version of job %q\", tag.Name, jobID)\n\t\t}\n\t\tif version.Version == jobVersion {\n\t\t\tjob = version\n\t\t}\n\t}\n\n\tif job == nil {\n\t\treturn fmt.Errorf(\"job %q version %d not found\", jobID, jobVersion)\n\t}\n\n\tversionCopy := job.Copy()\n\tversionCopy.VersionTag = tag\n\tversionCopy.ModifyIndex = index\n\n\tlatestJob, err := s.JobByID(nil, namespace, jobID)\n\tif err != nil {\n\t\treturn err\n\t}","sourceCodeStart":4917,"sourceCodeEnd":4953,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/state/state_store.go#L4917-L4953","documentation":"Nomad job version tags (used with the job versions API) must be unique per job: a tag name may be set or updated on one version, but cannot be applied to a different version while another version already carries it. The state store walks all stored versions of the job and rejects the request if the tag name is bound to a version other than the target.","triggerScenarios":"Calling the JobVersionTag apply endpoint (PUT /v1/job/:jobId/versions/:version/tag or JobApplyTag RPC) with a tag.Name that exists on version N while targeting version M != N.","commonSituations":"Teams reusing a stable tag like \"prod\" or \"canary\" for a newly promoted version without first unsetting it from the old version; automation scripts that re-tag after a rollback.","solutions":["Unset the tag from the old version first (JobRevert endpoints or the unset tag API), then apply it to the new version","Choose a unique tag name for the new version","List job versions (GET /v1/job/:jobId/versions) to find which version currently holds the tag"],"exampleFix":"// before: POST tag {\"Name\":\"stable\"} on version 5 while version 3 already has \"stable\"\n// after\n1) DELETE /v1/job/myjob/versions/tag?tag=stable  (unset from version 3)\n2) PUT /v1/job/myjob/versions/5/tag {\"Name\":\"stable\"}","handlingStrategy":"validation","validationCode":"versions, _, _ := client.Jobs().Versions(jobID, false, nil)\nfor _, v := range versions {\n  if v.VersionTag != nil && v.VersionTag.Name == newTag && v.Version != targetVersion {\n    // unset from v.Version first\n    client.Jobs().Revert... // or unsetTag(v.VersionTag.Name)\n  }\n}","typeGuard":null,"tryCatchPattern":"err := applyTag(jobID, version, tag)\nif err != nil && strings.Contains(err.Error(), \"already exists on a different version\") {\n  unsetTag(jobID, tag.Name)\n  err = applyTag(jobID, version, tag)\n}","preventionTips":["List existing version tags before applying a new one","Always unset tags from old versions when promoting a tag like 'stable'","Use unique, version-scoped tag names in automation"],"tags":["nomad","state-store","job-versions","tag-conflict"],"backgroundTag":"duplicate-tag-conflict","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}