hashicorp/nomad · error

namespace %q has non-terminal jobs in regions: %v

Error message

namespace %q has non-terminal jobs in regions: %v

What it means

Before deleting a namespace, Nomad checks every region for non-terminal (pending/running) jobs and allocations tied to that namespace via nonTerminalObjectsInNS. If any region still reports non-terminal objects, the delete is aborted with this error naming the offending regions. This prevents removing a namespace that still has live workloads.

Source

Thrown at nomad/namespace_endpoint.go:207

	for _, region := range regions {
		if region == thisRegion {
			continue
		}

		if remoteCheckFunc != nil {
			remoteTerminal, err := remoteCheckFunc(authToken, namespace, region)
			if err != nil {
				return err
			}
			if !remoteTerminal {
				terminal = append(terminal, region)
			}
		}
	}

	if len(terminal) != 0 {
		return fmt.Errorf(errorMsg, namespace, terminal)
	}

	return nil
}

// namespaceTerminalJobsLocally returns true if the namespace contains only
// terminal jobs in the local region.
func (n *Namespace) namespaceTerminalJobsLocally(namespace string, snap *state.StateSnapshot) (bool, error) {
	iter, err := snap.JobsByNamespace(nil, namespace, state.SortDefault)
	if err != nil {
		return false, err
	}
	for {
		raw := iter.Next()
		if raw == nil {
			break
		}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Stop or purge all jobs in the namespace in every listed region (nomad job stop -purge).
  2. Verify allocations are terminal (nomad status <job>); rebalance or clean orphaned allocs on dead nodes.
  3. Retry the namespace delete once all regions report only terminal objects.
  4. Check other regions explicitly if running a multi-region/federated cluster.

Example fix

// before
client.Namespaces().Delete(&api.NamespaceDeleteRequest{Namespaces: []string{"prod"}}) // fails: jobs still running
// after
for _, job := range jobsInNamespace("prod") {
    client.Jobs().Deregister(job.ID, true, &api.WriteOptions{Namespace: "prod"}) // purge
}
client.Namespaces().Delete(&api.NamespaceDeleteRequest{Namespaces: []string{"prod"}})
Defensive patterns

Strategy: validation

Validate before calling

jobs, _, _ := client.Jobs().List(&api.QueryOptions{Namespace: ns})
for _, j := range jobs {
    if j.Status != "dead" { return fmt.Errorf("job %s still %s", j.ID, j.Status) }
}
_, err := client.Namespaces().Delete(&api.NamespaceDeleteRequest{Namespaces: []string{ns}})

Try / catch

_, err := client.Namespaces().Delete(req)
if err != nil && strings.Contains(err.Error(), "non-terminal") {
    // purge remaining jobs in each listed region, then retry once
}

Prevention

When it happens

Trigger: Calling Namespace.Delete while jobs in the namespace are pending/running in one or more regions; orphaned non-terminal allocations on dead nodes; leftover workloads after a failed cleanup.

Common situations: Deleting namespaces during cluster teardown while a job is still running; multi-region deployments where a remote region still runs workloads; stuck allocations from a down node that never reached terminal state.

Related errors


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