hashicorp/nomad · error
tag %q already exists on a different version of job %q
Error message
tag %q already exists on a different version of job %q
What it means
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.
Source
Thrown at nomad/state/state_store.go:4935
}
return txn.Commit()
}
func (s *StateStore) updateJobVersionTagImpl(index uint64, namespace, jobID string, jobVersion uint64, tag *structs.JobVersionTag, txn *txn) error {
// Note: could use JobByIDAndVersion to get the specific version we want here,
// but then we'd have to make a second lookup to make sure we're not applying a duplicate tag name
versions, err := s.JobVersionsByID(nil, namespace, jobID)
if err != nil {
return err
}
var job *structs.Job
for _, version := range versions {
// Allow for a tag to be updated (new description, for example) but otherwise don't allow a same-tagname to a different version.
if version.VersionTag != nil && version.VersionTag.Name == tag.Name && version.Version != jobVersion {
return fmt.Errorf("tag %q already exists on a different version of job %q", tag.Name, jobID)
}
if version.Version == jobVersion {
job = version
}
}
if job == nil {
return fmt.Errorf("job %q version %d not found", jobID, jobVersion)
}
versionCopy := job.Copy()
versionCopy.VersionTag = tag
versionCopy.ModifyIndex = index
latestJob, err := s.JobByID(nil, namespace, jobID)
if err != nil {
return err
}View on GitHub (pinned to 482b49bf1a)
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
Example fix
// before: POST tag {"Name":"stable"} on version 5 while version 3 already has "stable"
// after
1) DELETE /v1/job/myjob/versions/tag?tag=stable (unset from version 3)
2) PUT /v1/job/myjob/versions/5/tag {"Name":"stable"} Defensive patterns
Strategy: validation
Validate before calling
versions, _, _ := client.Jobs().Versions(jobID, false, nil)
for _, v := range versions {
if v.VersionTag != nil && v.VersionTag.Name == newTag && v.Version != targetVersion {
// unset from v.Version first
client.Jobs().Revert... // or unsetTag(v.VersionTag.Name)
}
} Try / catch
err := applyTag(jobID, version, tag)
if err != nil && strings.Contains(err.Error(), "already exists on a different version") {
unsetTag(jobID, tag.Name)
err = applyTag(jobID, version, tag)
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- deleting job versions failed: %v
- failed to insert job into job_version table: %v
- failed to look up job versions for %q: %v
- failed to delete job %v (%d) from job_version
- job %q version %d not found
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/5e8a0d9441318d02.
Report an issue: GitHub.