hashicorp/nomad · error

can not delete default namespace

Error message

can not delete default namespace

What it means

DeleteNamespaces refuses to delete the built-in 'default' namespace (structs.DefaultNamespace). The default namespace is a system sentinel that jobs, ACLs, and API defaults rely on, so deleting it would break cluster invariants. The check runs before any state mutation.

Source

Thrown at nomad/namespace_endpoint.go:112

	if authErr != nil {
		return structs.ErrPermissionDenied
	}
	defer metrics.MeasureSince([]string{"nomad", "namespace", "delete_namespaces"}, time.Now())

	// Check management permissions
	if aclObj, err := n.srv.ResolveACL(args); err != nil {
		return err
	} else if !aclObj.IsManagement() {
		return structs.ErrPermissionDenied
	}

	// Validate at least one namespace
	if len(args.Namespaces) == 0 {
		return fmt.Errorf("must specify at least one namespace to delete")
	}

	if slices.Contains(args.Namespaces, structs.DefaultNamespace) {
		return fmt.Errorf("can not delete default namespace")
	}

	// snapshot the state once, because we'll be doing many checks and want
	// consistend state
	snap, err := n.srv.fsm.State().Snapshot()
	if err != nil {
		return err
	}

	var mErr multierror.Error
	for _, ns := range args.Namespaces {
		// make sure this namespace exists before we start making costly checks
		exists, _ := snap.NamespaceByName(nil, ns)
		if exists == nil {
			continue
		}

		// do a check across jobs, allocations, volumes and variables to make sure we're

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Remove "default" from the Namespaces list before calling Delete.
  2. Filter with slices.DeleteFunc(names, func(n string) bool { return n == "default" }).
  3. Migrate workloads to another namespace instead of trying to delete default.

Example fix

// before
client.Namespaces().Delete(&api.NamespaceDeleteRequest{Namespaces: allNames})
// after
names := slices.DeleteFunc(allNames, func(n string) bool { return n == structs.DefaultNamespace })
client.Namespaces().Delete(&api.NamespaceDeleteRequest{Namespaces: names})
Defensive patterns

Strategy: validation

Validate before calling

names := slices.DeleteFunc(names, func(n string) bool { return n == "default" })
if len(names) == 0 { return nil }
_, err := client.Namespaces().Delete(&api.NamespaceDeleteRequest{Namespaces: names})

Type guard

func deletableNamespaces(names []string) []string {
    out := make([]string, 0, len(names))
    for _, n := range names { if n != "default" { out = append(out, n) } }
    return out
}

Prevention

When it happens

Trigger: Including "default" in the Namespaces slice of a NamespaceDeleteRequest, e.g. deleting all namespaces from a wildcard listing without filtering out 'default'.

Common situations: Bulk cleanup scripts that enumerate and delete all namespaces; operators trying to 'reset' a cluster; tests reusing a wildcard delete helper.

Related errors


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