hashicorp/nomad · error · RegisterEnforceIndexErrPrefix

%s 0: job already exists

Error message

%s 0: job already exists

What it means

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.

Source

Thrown at nomad/structs/job.go:311

func (j *Job) RequiredScheduleTask() set.Collection[string] {
	result := set.New[string](len(j.TaskGroups))
	for _, tg := range j.TaskGroups {
		for _, t := range tg.Tasks {
			if t.Schedule != nil {
				result.Insert(tg.Name)
				break // to next TaskGroup
			}
		}
	}
	return result
}

// EnforceIndex checks the `EnforceIndex` logic: if the job exists (not `nil`)
// it must match the `index` argument and if `index == 0` the job must be `nil`.
func (j *Job) EnforceIndex(index uint64) error {
	if j != nil {
		if index == 0 {
			return fmt.Errorf("%s 0: job already exists", RegisterEnforceIndexErrPrefix)
		} else if index != j.JobModifyIndex {
			return fmt.Errorf("%s %d: job exists with conflicting job modify index: %d",
				RegisterEnforceIndexErrPrefix, index, j.JobModifyIndex)
		}
	} else if index != 0 {
		return fmt.Errorf("%s %d: job does not exist", RegisterEnforceIndexErrPrefix, index)
	}
	return nil
}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Delete the existing job first if a create-only register is intended
  2. Use the current JobModifyIndex instead of 0 to update the existing job
  3. Drop EnforceIndex if the create-vs-update distinction is not required

Example fix

// before
EnforceIndex: true, JobModifyIndex: 0 // create-only
// after
EnforceIndex: true, JobModifyIndex: <current JobModifyIndex from state> // update
Defensive patterns

Strategy: validation

Validate before calling

existing, _, err := client.Jobs().Info(jobID)
if err != nil && enforceIndex == 0 {
  // job absent, index 0 is safe
} else if _, ok := existing.(*api.Job); ok && enforceIndex == 0 {
  return errors.New("job exists; cannot register with EnforceIndex=0")
}

Try / catch

_, _, err := client.Jobs().Register(job, nil)
if err != nil && strings.Contains(err.Error(), "job already exists") {
  // fetch current index and re-register as update
}

Prevention

When it happens

Trigger: 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).

Common situations: '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.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/9de88cc426046f2e. Report an issue: GitHub.