{"record":{"id":"91b55da149f154d2","repo":"istio/istio","slug":"error-switching-to-ns-fd-v-v","errorCode":null,"errorMessage":"Error switching to ns fd %v: %v","messagePattern":"Error switching to ns fd (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":500,"severity":"error","filePath":"cni/pkg/nodeagent/netns_linux.go","lineNumber":69,"sourceCode":"\treturn stats.Ino, err\n}\n\nfunc OpenNetns(nspath string) (NetnsCloser, error) {\n\tn, err := netns.GetNS(nspath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ti, err := inodeForFd(n)\n\tif err != nil {\n\t\tn.Close()\n\t\treturn nil, err\n\t}\n\treturn &NetnsWrapper{innerNetns: n, inode: i}, nil\n}\n\nfunc NetnsSet(n NetnsFd) error {\n\tif err := unix.Setns(int(n.Fd()), unix.CLONE_NEWNET); err != nil {\n\t\treturn fmt.Errorf(\"Error switching to ns fd %v: %v\", n.Fd(), err)\n\t}\n\treturn nil\n}\n\n// inspired by netns.Do() but with an existing fd.\nfunc NetnsDo(fdable NetnsFd, toRun func() error) error {\n\tcontainedCall := func() error {\n\t\tthreadNS, err := netns.GetCurrentNS()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to open current netns: %v\", err)\n\t\t}\n\t\tdefer threadNS.Close()\n\n\t\t// switch to target namespace\n\t\tif err = NetnsSet(fdable); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tdefer func() {","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/istio/istio/blob/8dc789c5cf17517c64e3c36cb3288230f149dfae/cni/pkg/nodeagent/netns_linux.go#L51-L87","documentation":"unix.Setns(fd, CLONE_NEWNET) failed while switching the current thread into a pod's network namespace. Setns requires the fd to reference a live netns and the caller to hold CAP_SYS_ADMIN in the target namespace's user namespace.","triggerScenarios":"NetnsSet called with a closed/stale fd (pod netns already destroyed), fd not actually a netns fd, or the calling process lacks CAP_SYS_ADMIN/privileged — EINVAL for bad fd, EPERM for capability.","commonSituations":"istio-cni agent not privileged or missing CAP_SYS_ADMIN; race where the pod is deleted and its netns fd closed before the switch; seccomp profiles blocking setns; restricted PodSecurity policies.","solutions":["Run the agent privileged or with CAP_SYS_ADMIN (as istio-cni requires) and check PSA/PSP/SCC policies","Validate the fd is open and points to a netns before calling (fstat S_IFSOCK / check /proc/self/fd)","Handle EINVAL/EBADF races by re-fetching the netns handle or skipping cleanup for gone pods","Ensure seccomp profile allows setns"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// verify the fd is an open netns before setns\nvar st unix.Stat_t\nif err := unix.Fstat(int(fd.Fd()), &st); err != nil {\n    return fmt.Errorf(\"netns fd invalid: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if err := NetnsSet(nsFd); err != nil {\n    if errors.Is(err, syscall.EPERM) {\n        return errors.New(\"setns denied: run istio-cni with CAP_SYS_ADMIN/privileged\")\n    }\n    if errors.Is(err, syscall.EINVAL) {\n        return errors.New(\"setns: fd is not a network namespace (pod gone?)\")\n    }\n    return err\n}","preventionTips":["Hold the netns fd open only as long as needed; re-fetch on staleness","Run the CNI agent privileged/CAP_SYS_ADMIN; allow setns in seccomp","Pin goroutines that switch namespaces to a locked OS thread (runtime.LockOSThread)"],"tags":["namespaces","privileges","netlink","pod-netns","linux","istio-cni"],"backgroundTag":null,"analyzedSha":"8dc789c5cf17517c64e3c36cb3288230f149dfae","analyzedAt":"2026-08-15T15:16:55.434Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}