{"record":{"id":"800329740f06eb9e","repo":"gastownhall/beads","slug":"pidfd-open-d-w","errorCode":null,"errorMessage":"pidfd open %d: %w","messagePattern":"pidfd open (.+?): %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/dbproxy/proxy/unverified_process_linux.go","lineNumber":40,"sourceCode":"type unverifiedProcess struct {\n\tpid   int\n\tpidfd int // -1 when the kernel has no pidfd support\n}\n\n// openUnverifiedProcess opens a stable handle for pid. gone reports a PID\n// that no longer exists.\nfunc openUnverifiedProcess(pid int) (proc *unverifiedProcess, gone bool, err error) {\n\tfd, err := unix.PidfdOpen(pid, 0)\n\tif err == nil {\n\t\treturn &unverifiedProcess{pid: pid, pidfd: fd}, false, nil\n\t}\n\tif errors.Is(err, unix.ESRCH) {\n\t\treturn nil, true, nil\n\t}\n\tif errors.Is(err, unix.ENOSYS) {\n\t\treturn &unverifiedProcess{pid: pid, pidfd: -1}, false, nil\n\t}\n\treturn nil, false, fmt.Errorf(\"pidfd open %d: %w\", pid, err)\n}\n\nfunc (p *unverifiedProcess) executableBasename() (basename string, gone bool, err error) {\n\treturn processExecutableBasename(p.pid)\n}\n\n// commandLineContains reports whether the process command line contains\n// needle. The managed proxy child is spawned as \"db-proxy-child --root\n// <rootDir>\", so a workspace's own processes always match their root path.\nfunc (p *unverifiedProcess) commandLineContains(needle string) (matched bool, gone bool, err error) {\n\tdata, err := os.ReadFile(\"/proc/\" + strconv.Itoa(p.pid) + \"/cmdline\")\n\tif err != nil {\n\t\tif errors.Is(err, fs.ErrNotExist) || errors.Is(err, unix.ESRCH) {\n\t\t\treturn false, true, nil\n\t\t}\n\t\treturn false, false, fmt.Errorf(\"read cmdline for pid %d: %w\", p.pid, err)\n\t}\n\tif len(data) == 0 {","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/dbproxy/proxy/unverified_process_linux.go#L22-L58","documentation":"On Linux, openUnverifiedProcess first tries pidfd_open to get a stable handle on the PID (preventing PID-recycling races). If pidfd_open fails with anything other than ESRCH (gone) or ENOSYS (kernel too old, fallback allowed), the error is wrapped here and the operation aborts. The proxy needs either a pidfd or the ENOSYS fallback to inspect the process safely.","triggerScenarios":"openUnverifiedProcess calls pidfd_open(pid) on Linux and the syscall returns an unexpected errno — e.g. EMFILE/ENFILE (fd/table exhaustion), EINVAL (bad flags/kernel), EPERM in hardened environments.","commonSituations":"Very old kernels (<5.3) lacking pidfd_open combined with seccomp returning something other than ENOSYS; fd limits exhausted after long daemon uptime; restricted containers/seccomp profiles that return EPERM for unknown syscalls.","solutions":["Raise the process fd limit (ulimit -n) if EMFILE/ENFILE is the cause.","Upgrade the kernel to >=5.3 so pidfd_open is supported normally.","Adjust seccomp/container profile to allow pidfd_open (or return ENOSYS so the fallback path is used).","Retry the stop operation — transient fd exhaustion often clears."],"exampleFix":"// before: seccomp blocks pidfd_open with EPERM\n// docker run --security-opt seccomp=default.json ...\n// after: allow or downgrade unknown syscalls to ENOSYS\n// seccomp profile: {\"names\":[\"pidfd_open\"],\"action\":\"SCMP_ACT_ERRNO\",\"errnoRet\":38}","handlingStrategy":"retry","validationCode":"// probe pidfd support before relying on the fast path\nfd, _, errno := unix.Syscall(unix.SYS_PIDFD_OPEN, uintptr(pid), 0, 0)\nsupported := errno != unix.ENOSYS && errno != unix.EPERM\nif !supported { /* expect/require the ENOSYS fallback or skip force-stop */ }","typeGuard":null,"tryCatchPattern":"proc, gone, err := openUnverifiedProcess(pid)\nif err != nil {\n    if errors.Is(err, unix.EMFILE) || errors.Is(err, unix.ENFILE) {\n        // transient fd exhaustion: wait and retry once\n    }\n    return err\n}","preventionTips":["Run on kernel >= 5.3 where pidfd_open is standard.","Raise the fd limit (ulimit -n) for long-running daemons.","Use seccomp profiles that return ENOSYS (not EPERM) for unknown syscalls so the fallback path activates.","Close leaked pidfds/fds in tooling that holds process handles."],"tags":["go","linux","pidfd","syscall","kernel"],"backgroundTag":"pidfd-open-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}