{"record":{"id":"1078589cf0ebc80e","repo":"hashicorp/nomad","slug":"error-switching-to-ns-v-v","errorCode":null,"errorMessage":"Error switching to ns %v: %v","messagePattern":"Error switching to ns (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/lib/nsutil/ns_linux.go","lineNumber":67,"sourceCode":"\tif err := ns.errorIfClosed(); err != nil {\n\t\treturn err\n\t}\n\n\tif err := ns.file.Close(); err != nil {\n\t\treturn fmt.Errorf(\"Failed to close %q: %v\", ns.file.Name(), err)\n\t}\n\tns.closed = true\n\n\treturn nil\n}\n\nfunc (ns *netNS) Set() error {\n\tif err := ns.errorIfClosed(); err != nil {\n\t\treturn err\n\t}\n\n\tif err := unix.Setns(int(ns.Fd()), unix.CLONE_NEWNET); err != nil {\n\t\treturn fmt.Errorf(\"Error switching to ns %v: %v\", ns.file.Name(), err)\n\t}\n\n\treturn nil\n}\n\ntype NetNS interface {\n\t// Executes the passed closure in this object's network namespace,\n\t// attempting to restore the original namespace before returning.\n\t// However, since each OS thread can have a different network namespace,\n\t// and Go's thread scheduling is highly variable, callers cannot\n\t// guarantee any specific namespace is set unless operations that\n\t// require that namespace are wrapped with Do().  Also, no code called\n\t// from Do() should call runtime.UnlockOSThread(), or the risk\n\t// of executing code in an incorrect namespace will be greater.  See\n\t// https://github.com/golang/go/wiki/LockOSThread for further details.\n\tDo(toRun func(NetNS) error) error\n\n\t// Sets the current network namespace to this object's network namespace.","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/lib/nsutil/ns_linux.go#L49-L85","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Ensure the process has CAP_SYS_ADMIN (run as root or add the capability) since setns(CLONE_NEWNET) requires it","Verify the target namespace still exists (the owning container/task has not exited) and re-open it via GetNS if needed","Check seccomp/AppArmor/container runtime profiles allow setns","Do not call Set() on a NetNS after Close(); keep the handle open for the duration of the switch","Inspect the wrapped %v kernel error (EPERM vs EINVAL vs EBADF) to pinpoint the cause"],"exampleFix":"// before\nif err := ns.Set(); err != nil {\n    return err // fails with EPERM in unprivileged container\n}\n// after\nif !hasCapSysAdmin() {\n    return fmt.Errorf(\"setns requires CAP_SYS_ADMIN; run privileged\")\n}\nif err := ns.Set(); err != nil {\n    return fmt.Errorf(\"switch to netns failed: %w\", err)\n}","handlingStrategy":"try-catch","validationCode":"func canSetns() error {\n    if _, err := os.Stat(\"/proc/self/ns/net\"); err != nil {\n        return fmt.Errorf(\"procfs unavailable: %w\", err)\n    }\n    if !hasCapSysAdmin() {\n        return fmt.Errorf(\"CAP_SYS_ADMIN required for setns\")\n    }\n    return nil\n}","typeGuard":"func nsUsable(ns NetNS) bool {\n    n, ok := ns.(*netNS)\n    return ok && n.file != nil && !n.closed\n}","tryCatchPattern":"if err := ns.Set(); err != nil {\n    var perr syscall.Errno\n    if errors.As(err, &perr) && perr == syscall.EPERM {\n        return fmt.Errorf(\"insufficient privileges to switch netns: %w\", err)\n    }\n    return fmt.Errorf(\"netns switch failed: %w\", err)\n}","preventionTips":["Run components that switch namespaces with CAP_SYS_ADMIN","Never use a NetNS handle after Close(); track its lifetime","Confirm the owning container/task is alive before using its netns","Log the wrapped kernel errno to distinguish EPERM/EINVAL/EBADF"],"tags":["linux","network-namespace","namespaces","permissions"],"backgroundTag":"netns-setns-failed","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}