{"record":{"id":"e1a98479c5afff98","repo":"hashicorp/nomad","slug":"current-job-has-version-d-enforcing-version-d","errorCode":null,"errorMessage":"Current job has version %d; enforcing version %d","messagePattern":"Current job has version (.+?); enforcing version (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/job_endpoint.go","lineNumber":610,"sourceCode":"\t// Build the register request\n\trevJob := jobV.Copy()\n\n\t// Clear out the VersionTag to prevent tag duplication\n\trevJob.VersionTag = nil\n\n\t// Set the stable flag to false as this is functionally a new registration\n\t// and should handle deployment updates\n\trevJob.Stable = false\n\n\treg := &structs.JobRegisterRequest{\n\t\tJob:          revJob,\n\t\tWriteRequest: args.WriteRequest,\n\t}\n\n\t// If the request is enforcing the existing version do a check.\n\tif args.EnforcePriorVersion != nil {\n\t\tif cur.Version != *args.EnforcePriorVersion {\n\t\t\treturn fmt.Errorf(\"Current job has version %d; enforcing version %d\", cur.Version, *args.EnforcePriorVersion)\n\t\t}\n\n\t\treg.EnforceIndex = true\n\t\treg.JobModifyIndex = cur.JobModifyIndex\n\t}\n\n\t// Register the version.\n\tallowedPermissions := []string{acl.NamespaceCapabilityRevertJob}\n\treturn j.doRegister(aclObj, allowedPermissions, reg, reply)\n}\n\n// Stable is used to mark the job version as stable\nfunc (j *Job) Stable(args *structs.JobStabilityRequest, reply *structs.JobStabilityResponse) error {\n\tauthErr := j.srv.Authenticate(j.ctx, args)\n\tif done, err := j.srv.forward(\"Job.Stable\", args, args, reply); done {\n\t\treturn err\n\t}\n\tj.srv.MeasureRPCRate(\"job\", structs.RateMetricWrite, args)","sourceCodeStart":592,"sourceCodeEnd":628,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/job_endpoint.go#L592-L628","documentation":"Revert supports an optional EnforcePriorVersion check: the caller can require that the job is still at an expected version before the rollback is applied, guarding against concurrent modifications. If the job's current version (cur.Version) differs from *args.EnforcePriorVersion, the RPC aborts with \"Current job has version %d; enforcing version %d\". It is an optimistic-concurrency guard, not a data corruption.","triggerScenarios":"Calling Job.Revert with a non-nil EnforcePriorVersion pointer whose value no longer matches the job's current registered version — e.g. the job was updated/reverted by someone else between when you read the version and issued the revert.","commonSituations":"CI/CD automation holding a stale expected version while another pipeline deploys; two operators reverting simultaneously; long-lived scripts built against an old snapshot of job state; retry logic replaying a revert with an outdated EnforcePriorVersion.","solutions":["Re-read the job's current version (`nomad job inspect` / Jobs().Info) and retry the revert with the fresh value","If the new current version is acceptable, drop the EnforcePriorVersion guard (pass nil) and revert directly","Coordinate/serialize deployments so concurrent writers don't race the revert","Implement retry-with-refresh: on this error, re-fetch version, re-verify, and re-issue the revert"],"exampleFix":"// before (stale expected version)\nenforce := uint64(4)\nclient.Jobs().Revert(\"webapp\", 4, 7, &enforce, nil, nil)\n// after (refresh before enforcing)\njob, _, _ := client.Jobs().Info(\"webapp\", nil)\nenforce := *job.Version\nclient.Jobs().Revert(\"webapp\", enforce, 7, &enforce, nil, nil)","handlingStrategy":"retry","validationCode":"job, _, err := client.Jobs().Info(jobID, nil)\nif err != nil { return err }\nexpected := *job.Version // refresh immediately before the enforced revert","typeGuard":"func versionMatches(job *api.Job, expected uint64) bool { return job != nil && job.Version != nil && *job.Version == expected }","tryCatchPattern":"for attempt := 0; attempt < 3; attempt++ {\n    job, _, _ := client.Jobs().Info(jobID, nil)\n    exp := *job.Version\n    _, _, err := client.Jobs().Revert(jobID, exp, target, &exp, nil, nil)\n    if err == nil { break }\n    if !strings.Contains(err.Error(), \"enforcing version\") { return err }\n    time.Sleep(time.Second) // version raced; refresh and retry\n}","preventionTips":["Re-read job state immediately before every enforced revert","Serialize deploy/rollback workflows so only one writer mutates a job at a time","Treat this error as a signal of concurrent modification, not a bug","Drop EnforcePriorVersion (pass nil) only when you accept any current version"],"tags":["nomad","job-revert","optimistic-concurrency","version-conflict"],"backgroundTag":"concurrent-modification-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"}