{"record":{"id":"14437bb2288df509","repo":"hashicorp/nomad","slug":"s-d-job-exists-with-conflicting-job-modify-inde","errorCode":null,"errorMessage":"%s %d: job exists with conflicting job modify index: %d","messagePattern":"(.+?) (.+?): job exists with conflicting job modify index: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"nomad/job_endpoint.go","lineNumber":1070,"sourceCode":"\t\t// Update group count\n\t\tgroup.Count = newCount\n\t\tjob.SubmitTime = now\n\n\t\t// Block scaling event if there's an active deployment\n\t\tdeployment, err := snap.LatestDeploymentByJobID(ws, namespace, args.JobID)\n\t\tif err != nil {\n\t\t\tj.logger.Error(\"unable to lookup latest deployment\", \"error\", err)\n\t\t\treturn err\n\t\t}\n\n\t\tif deployment != nil && deployment.Active() && deployment.JobCreateIndex == job.CreateIndex {\n\t\t\treturn structs.NewErrRPCCoded(400, \"job scaling blocked due to active deployment\")\n\t\t}\n\n\t\t// If JobModifyIndex set, check it before trying to apply\n\t\tif args.JobModifyIndex > 0 {\n\t\t\tif args.JobModifyIndex != job.JobModifyIndex {\n\t\t\t\treturn fmt.Errorf(\"%s %d: job exists with conflicting job modify index: %d\",\n\t\t\t\t\tstructs.RegisterEnforceIndexErrPrefix, args.JobModifyIndex, job.JobModifyIndex)\n\t\t\t}\n\t\t}\n\n\t\t// Commit the job update\n\t\t_, jobModifyIndex, err := j.srv.raftApply(\n\t\t\tstructs.JobRegisterRequestType,\n\t\t\tstructs.JobRegisterRequest{\n\t\t\t\tJob:            job,\n\t\t\t\tEnforceIndex:   true,\n\t\t\t\tJobModifyIndex: job.JobModifyIndex,\n\t\t\t\tPolicyOverride: args.PolicyOverride,\n\t\t\t\tWriteRequest:   args.WriteRequest,\n\t\t\t},\n\t\t)\n\t\tif err != nil {\n\t\t\tj.logger.Error(\"job register for scale failed\", \"error\", err)\n\t\t\treturn err","sourceCodeStart":1052,"sourceCodeEnd":1088,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/job_endpoint.go#L1052-L1088","documentation":"The Job.Scale RPC supports optimistic concurrency: if the caller passes JobModifyIndex, Nomad verifies it still matches the job's current JobModifyIndex before applying the scale. A mismatch means the job was modified (registered, scaled, etc.) since the caller read it, so the scale is rejected with the RegisterEnforceIndexErrPrefix to force a re-read.","triggerScenarios":"POST /v1/job/<id>/scale with args.JobModifyIndex > 0 that differs from the live job.JobModifyIndex — concurrent scaling/deploys, a stale job object cached from an earlier read, or an autoscaler racing a human 'nomad job run'.","commonSituations":"Autoscaler and CI pipeline scaling the same job simultaneously; long-lived scripts using an index captured minutes earlier; clients copying JobModifyIndex from a different job's info response.","solutions":["Re-fetch the current job (GET /v1/job/<id>), take its fresh JobModifyIndex, and retry the scale","Retry with backoff on conflict since concurrent writers resolve quickly","Pass JobModifyIndex: 0 to skip the check only if last-write-wins is acceptable (risky)","Serialize scaling for the job through a single controller/lock"],"exampleFix":"// before\njob, _, _ := client.Jobs().Info(\"web\", nil)\ntime.Sleep(5 * time.Minute)\nclient.Jobs().Scale(\"web\", \"web\", \"group\", &job.JobModifyIndex, ...)\n// after\njob, _, _ := client.Jobs().Info(\"web\", nil)\n_, _, err := client.Jobs().Scale(\"web\", \"web\", \"group\", job.JobModifyIndex, ...)\nif err != nil {\n    job, _, _ = client.Jobs().Info(\"web\", nil) // refresh index and retry\n}","handlingStrategy":"retry","validationCode":"job, _, _ := client.Jobs().Info(jobID, nil)\nmodifyIndex := *job.JobModifyIndex // read immediately before scaling","typeGuard":null,"tryCatchPattern":"for i := 0; i < 3; i++ {\n\tjob, _, _ = client.Jobs().Info(jobID, nil)\n\t_, _, err := client.Jobs().Scale(jobID, jobID, group, job.JobModifyIndex, uint64(count), \"api\", false, nil)\n\tif err == nil { break }\n\tif !strings.Contains(err.Error(), \"conflicting job modify index\") { return err }\n\ttime.Sleep(time.Duration(1<<i) * time.Second)\n}","preventionTips":["Always read JobModifyIndex immediately before scaling","Add exponential-backoff retry around scale calls","Avoid concurrent autoscaler + manual scaling of the same job, or use a lock"],"tags":["nomad","conflict","optimistic-concurrency","scaling"],"backgroundTag":"conflict-modify-index-mismatch","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"}