hashicorp/nomad · error

namespace %q contains at least one non-terminal job %q. All

Error message

namespace %q contains at least one non-terminal job %q. All jobs must be terminal in namespace before it can be deleted

What it means

DeleteNamespace refuses to remove a namespace that still contains at least one job whose status is not "dead". Nomad requires every job in the namespace to be terminal before the namespace can be deleted, and the error names the offending job ID.

Source

Thrown at nomad/state/state_store.go:7145

		if ns.Name == structs.DefaultNamespace {
			return fmt.Errorf("default namespace can not be deleted")
		}

		// Ensure that the namespace doesn't have any non-terminal jobs
		iter, err := s.jobsByNamespaceImpl(nil, name, txn, SortDefault)
		if err != nil {
			return err
		}

		for {
			raw := iter.Next()
			if raw == nil {
				break
			}
			job := raw.(*structs.Job)

			if job.Status != structs.JobStatusDead {
				return fmt.Errorf("namespace %q contains at least one non-terminal job %q. "+
					"All jobs must be terminal in namespace before it can be deleted", name, job.ID)
			}
		}

		vIter, err := s.csiVolumesByNamespaceImpl(txn, nil, name, "")
		if err != nil {
			return err
		}
		rawVol := vIter.Next()
		if rawVol != nil {
			vol := rawVol.(*structs.CSIVolume)
			return fmt.Errorf("namespace %q contains at least one CSI volume %q. "+
				"All CSI volumes in namespace must be deleted before it can be deleted", name, vol.ID)
		}

		varIter, err := s.getVariablesByNamespaceImpl(txn, nil, name)
		if err != nil {
			return err

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Stop all jobs in the namespace (`nomad job stop -namespace <ns> <job>`) and wait for status to become dead, then retry deletion.
  2. Purge stopped jobs with `nomad job stop -purge` to clear them, then delete the namespace.
  3. Identify the job named in the error and inspect why it is non-terminal (e.g., periodic or system jobs must be disabled/purged first).

Example fix

# before
nomad namespace delete team-a
# after
nomad job stop -namespace team-a -purge <job-id>
nomad namespace delete team-a
Defensive patterns

Strategy: validation

Validate before calling

jobs, _, _ := client.Jobs().List(&nomad.QueryOptions{Namespace: ns})
for _, j := range jobs {
    if j.Status != "dead" {
        return fmt.Errorf("job %s in %s is %s; stop it first", j.ID, ns, j.Status)
    }
}

Try / catch

if strings.Contains(err.Error(), "non-terminal job") {
    // extract job ID from the message and stop/purge it before retrying
}

Prevention

When it happens

Trigger: DELETE /v1/namespace/<name> (or `nomad namespace delete`) while any job in that namespace is pending/running; only dead jobs are acceptable.

Common situations: Deleting a namespace during tenant offboarding while periodic/system jobs still live there; a job stuck in pending preventing cleanup; forgotten parameterized/dispatched jobs.

Related errors


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