hashicorp/nomad · error

Error switching to ns %v: %v

Error message

Error switching to ns %v: %v

What it means

This error is returned by netNS.Set() when the setns(2) syscall (via unix.Setns with CLONE_NEWNET) fails to move the calling thread into the network namespace referenced by this open NetNS handle. It wraps the underlying OS error together with the namespace file name, so it indicates the file descriptor was valid but the kernel refused the namespace switch.

Source

Thrown at client/lib/nsutil/ns_linux.go:67

	if err := ns.errorIfClosed(); err != nil {
		return err
	}

	if err := ns.file.Close(); err != nil {
		return fmt.Errorf("Failed to close %q: %v", ns.file.Name(), err)
	}
	ns.closed = true

	return nil
}

func (ns *netNS) Set() error {
	if err := ns.errorIfClosed(); err != nil {
		return err
	}

	if err := unix.Setns(int(ns.Fd()), unix.CLONE_NEWNET); err != nil {
		return fmt.Errorf("Error switching to ns %v: %v", ns.file.Name(), err)
	}

	return nil
}

type NetNS interface {
	// Executes the passed closure in this object's network namespace,
	// attempting to restore the original namespace before returning.
	// However, since each OS thread can have a different network namespace,
	// and Go's thread scheduling is highly variable, callers cannot
	// guarantee any specific namespace is set unless operations that
	// require that namespace are wrapped with Do().  Also, no code called
	// from Do() should call runtime.UnlockOSThread(), or the risk
	// of executing code in an incorrect namespace will be greater.  See
	// https://github.com/golang/go/wiki/LockOSThread for further details.
	Do(toRun func(NetNS) error) error

	// Sets the current network namespace to this object's network namespace.

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Ensure the process has CAP_SYS_ADMIN (run as root or add the capability) since setns(CLONE_NEWNET) requires it
  2. Verify the target namespace still exists (the owning container/task has not exited) and re-open it via GetNS if needed
  3. Check seccomp/AppArmor/container runtime profiles allow setns
  4. Do not call Set() on a NetNS after Close(); keep the handle open for the duration of the switch
  5. Inspect the wrapped %v kernel error (EPERM vs EINVAL vs EBADF) to pinpoint the cause

Example fix

// before
if err := ns.Set(); err != nil {
    return err // fails with EPERM in unprivileged container
}
// after
if !hasCapSysAdmin() {
    return fmt.Errorf("setns requires CAP_SYS_ADMIN; run privileged")
}
if err := ns.Set(); err != nil {
    return fmt.Errorf("switch to netns failed: %w", err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

func canSetns() error {
    if _, err := os.Stat("/proc/self/ns/net"); err != nil {
        return fmt.Errorf("procfs unavailable: %w", err)
    }
    if !hasCapSysAdmin() {
        return fmt.Errorf("CAP_SYS_ADMIN required for setns")
    }
    return nil
}

Type guard

func nsUsable(ns NetNS) bool {
    n, ok := ns.(*netNS)
    return ok && n.file != nil && !n.closed
}

Try / catch

if err := ns.Set(); err != nil {
    var perr syscall.Errno
    if errors.As(err, &perr) && perr == syscall.EPERM {
        return fmt.Errorf("insufficient privileges to switch netns: %w", err)
    }
    return fmt.Errorf("netns switch failed: %w", err)
}

Prevention

When it happens

Trigger: Calling Set() (directly or via Do()) on a NetNS whose fd is no longer valid for setns — e.g. the namespace was destroyed, the process lacks CAP_SYS_ADMIN, or the fd was closed concurrently (which makes unix.Fd() reuse invalid).

Common situations: Running the client without root/CAP_SYS_ADMIN in a container missing SYS_ADMIN; a task's network namespace (e.g. a docker bridge ns) was torn down while the handle was still in use; seccomp/AppArmor policies blocking setns; using the handle after garbage collection closed the underlying file.

Related errors


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