{"record":{"id":"9de88cc426046f2e","repo":"hashicorp/nomad","slug":"s-0-job-already-exists","errorCode":null,"errorMessage":"%s 0: job already exists","messagePattern":"(.+?) 0: job already exists","errorType":"validation","errorClass":"RegisterEnforceIndexErrPrefix","httpStatus":null,"severity":"error","filePath":"nomad/structs/job.go","lineNumber":311,"sourceCode":"func (j *Job) RequiredScheduleTask() set.Collection[string] {\n\tresult := set.New[string](len(j.TaskGroups))\n\tfor _, tg := range j.TaskGroups {\n\t\tfor _, t := range tg.Tasks {\n\t\t\tif t.Schedule != nil {\n\t\t\t\tresult.Insert(tg.Name)\n\t\t\t\tbreak // to next TaskGroup\n\t\t\t}\n\t\t}\n\t}\n\treturn result\n}\n\n// EnforceIndex checks the `EnforceIndex` logic: if the job exists (not `nil`)\n// it must match the `index` argument and if `index == 0` the job must be `nil`.\nfunc (j *Job) EnforceIndex(index uint64) error {\n\tif j != nil {\n\t\tif index == 0 {\n\t\t\treturn fmt.Errorf(\"%s 0: job already exists\", RegisterEnforceIndexErrPrefix)\n\t\t} else if index != j.JobModifyIndex {\n\t\t\treturn fmt.Errorf(\"%s %d: job exists with conflicting job modify index: %d\",\n\t\t\t\tRegisterEnforceIndexErrPrefix, index, j.JobModifyIndex)\n\t\t}\n\t} else if index != 0 {\n\t\treturn fmt.Errorf(\"%s %d: job does not exist\", RegisterEnforceIndexErrPrefix, index)\n\t}\n\treturn nil\n}\n","sourceCodeStart":293,"sourceCodeEnd":321,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/job.go#L293-L321","documentation":"Job.EnforceIndex implements the EnforceIndex (compare-and-set) semantics of job registration: if the job already exists, the caller may not request index 0 (which means 'job must not exist'). The RegisterEnforceIndexErrPrefix is prepended to every message.","triggerScenarios":"Calling the job register API with EnforceIndex=true and EnforceIndex=0 while a job with the same ID/namespace already exists in state (upsertJobImpl path).","commonSituations":"'Job must not exist' guard (EnforceIndex=0) used for create-only deploys, but the job was already deployed; race where two pipelines register the same job; stale assumption after a failed delete.","solutions":["Delete the existing job first if a create-only register is intended","Use the current JobModifyIndex instead of 0 to update the existing job","Drop EnforceIndex if the create-vs-update distinction is not required"],"exampleFix":"// before\nEnforceIndex: true, JobModifyIndex: 0 // create-only\n// after\nEnforceIndex: true, JobModifyIndex: <current JobModifyIndex from state> // update","handlingStrategy":"validation","validationCode":"existing, _, err := client.Jobs().Info(jobID)\nif err != nil && enforceIndex == 0 {\n  // job absent, index 0 is safe\n} else if _, ok := existing.(*api.Job); ok && enforceIndex == 0 {\n  return errors.New(\"job exists; cannot register with EnforceIndex=0\")\n}","typeGuard":null,"tryCatchPattern":"_, _, err := client.Jobs().Register(job, nil)\nif err != nil && strings.Contains(err.Error(), \"job already exists\") {\n  // fetch current index and re-register as update\n}","preventionTips":["Fetch job state before choosing an EnforceIndex value","Handle create-vs-update explicitly in deploy scripts","Use namespaces deliberately; verify the target namespace"],"tags":["nomad","job-register","enforce-index","cas"],"backgroundTag":"enforce-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"}