{"record":{"id":"291c34165cf171fe","repo":"hashicorp/nomad","slug":"failed-to-get-the-current-netns-v","errorCode":null,"errorMessage":"failed to get the current netns: %v","messagePattern":"failed to get the current netns: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/lib/nsutil/netns_linux.go","lineNumber":99,"sourceCode":"\t// is in-use\n\tdefer os.RemoveAll(nsPath)\n\n\tvar wg sync.WaitGroup\n\twg.Add(1)\n\n\t// do namespace work in a dedicated goroutine, so that we can safely\n\t// Lock/Unlock OSThread without upsetting the lock/unlock state of\n\t// the caller of this function\n\tgo (func() {\n\t\tdefer wg.Done()\n\t\truntime.LockOSThread()\n\t\t// Don't unlock. By not unlocking, golang will kill the OS thread when the\n\t\t// goroutine is done (for go1.10+)\n\n\t\tvar origNS NetNS\n\t\torigNS, err = GetNS(getCurrentThreadNetNSPath())\n\t\tif err != nil {\n\t\t\terr = fmt.Errorf(\"failed to get the current netns: %v\", err)\n\t\t\treturn\n\t\t}\n\t\tdefer origNS.Close()\n\n\t\t// create a new netns on the current thread\n\t\terr = unix.Unshare(unix.CLONE_NEWNET)\n\t\tif err != nil {\n\t\t\terr = fmt.Errorf(\"error from unshare: %v\", err)\n\t\t\treturn\n\t\t}\n\n\t\t// Put this thread back to the orig ns, since it might get reused (pre go1.10)\n\t\tdefer origNS.Set()\n\n\t\t// bind mount the netns from the current thread (from /proc) onto the\n\t\t// mount point. This causes the namespace to persist, even when there\n\t\t// are no threads in the ns.\n\t\terr = unix.Mount(getCurrentThreadNetNSPath(), nsPath, \"none\", unix.MS_BIND, \"\")","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/lib/nsutil/netns_linux.go#L81-L117","documentation":"Inside a locked OS thread, NewNS first obtains a handle to the thread's current network namespace via GetNS(getCurrentThreadNetNSPath()). If that fails, the error is wrapped as 'failed to get the current netns'. This typically means the per-thread namespace file under /proc could not be opened.","triggerScenarios":"GetNS on /proc/<tid>/ns/net fails while switching into a new namespace during NewNS — e.g. /proc not mounted, missing read permission on the ns file, or the namespace file disappeared because the thread exited.","commonSituations":"Containers without /proc mounted (rare but possible with custom runtime configs); host with hidepid mount option on /proc restricting access; highly restricted seccomp profiles blocking open of /proc files.","solutions":["Ensure /proc is mounted with default options in the container/runtime","Check file permissions on /proc/self/ns/net (readable by the process user)","Verify no seccomp/LSM policy blocks opening /proc/*/ns/* files","Confirm the Go runtime version is modern (go1.10+ behavior of thread lifetime is assumed by this code)"],"exampleFix":"// before: /proc not mounted in container\n// after: mount proc in container spec\n// mounts: [{destination: \"/proc\", type: \"proc\", source: \"proc\"}]\nns, err := nsutil.NewNS()","handlingStrategy":"validation","validationCode":"if _, err := os.Stat(\"/proc/self/ns/net\"); err != nil {\n    return fmt.Errorf(\"/proc namespaces unavailable: %v\", err)\n}","typeGuard":null,"tryCatchPattern":"ns, err := nsutil.NewNS()\nif err != nil && strings.Contains(err.Error(), \"failed to get the current netns\") {\n    return fmt.Errorf(\"cannot access /proc/<tid>/ns/net; check /proc mount and permissions: %w\", err)\n}","preventionTips":["Ensure /proc is mounted with default options in containers","Avoid hidepid /proc mounts for processes creating netns","Do not block opens of /proc/*/ns/* via seccomp/LSM policies","Keep /proc/self/ns/net readable by the running user"],"tags":["linux","network-namespace","procfs"],"backgroundTag":"netns-open-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"}