{"record":{"id":"4a430ae058a30423","repo":"gastownhall/beads","slug":"procid-pidfd-open-d-w","errorCode":null,"errorMessage":"procid: pidfd open %d: %w","messagePattern":"procid: pidfd open (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/procid/procid_linux.go","lineNumber":72,"sourceCode":"\t\t\treturn false, nil\n\t\t}\n\t\treturn false, err\n\t}\n\treturn current == tok, nil\n}\n\n// Open verifies pid's token and opens a handle suitable for safe signaling.\n//\n// The pidfd is opened before the token check: a pidfd pins the PID number\n// against reuse, so verifying afterwards proves the fd refers to the process\n// the token describes. Verifying first would leave a window where the\n// verified process exits, the PID is recycled, and the pidfd targets the\n// unrelated replacement.\nfunc Open(pid int, tok Token) (*Handle, error) {\n\tfd, err := pidfdOpen(pid, 0)\n\tif err != nil {\n\t\tif !errors.Is(err, unix.ENOSYS) {\n\t\t\treturn nil, fmt.Errorf(\"procid: pidfd open %d: %w\", pid, err)\n\t\t}\n\t\t// Kernel without pidfds: fall back to verify-then-signal, which\n\t\t// retains the documented small PID-reuse race.\n\t\tmatch, verifyErr := Verify(pid, tok)\n\t\tif verifyErr != nil {\n\t\t\treturn nil, verifyErr\n\t\t}\n\t\tif !match {\n\t\t\treturn nil, fmt.Errorf(\"procid: process %d does not match token\", pid)\n\t\t}\n\t\treturn &Handle{pid: pid, token: tok, pidfd: -1}, nil\n\t}\n\tmatch, verifyErr := Verify(pid, tok)\n\tif verifyErr != nil {\n\t\t_ = unix.Close(fd)\n\t\treturn nil, verifyErr\n\t}\n\tif !match {","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/procid/procid_linux.go#L54-L90","documentation":"On Linux, Open first calls pidfd_open to pin the PID against reuse. If that syscall fails with anything other than ENOSYS (kernel too old), the error is wrapped and returned — the handle could not be created safely. Typical errnos are ESRCH (process already gone), EINVAL, EMFILE/ENFILE (fd exhaustion), or EPERM in restricted environments (seccomp/containers blocking pidfd_open).","triggerScenarios":"procid.Open on Linux where unix.PidfdOpen fails with ESRCH (target exited before Open), EMFILE/ENFILE (process/file descriptor limit reached), EPERM (seccomp filter blocks pidfd_open), EINVAL.","commonSituations":"Killing an already-dead recorded PID; containers with restrictive seccomp profiles (older Docker default) that deny pidfd syscalls; hitting RLIMIT_NOFILE in servers with many open fds; very old kernels (<5.3) return ENOSYS and fall back instead — those do NOT produce this error.","solutions":["Check errors.Is(err, unix.ESRCH): the process is already gone; reconcile and skip.","Check errors.Is(err, unix.EMFILE) || errors.Is(err, unix.ENFILE): close leaked fds / raise RLIMIT_NOFILE, then retry.","If running in a container, update the seccomp/runtime profile to allow pidfd_open, or upgrade container runtime.","Upgrade the kernel to >=5.3 so pidfd is available (older kernels fall back via ENOSYS path, which is different)."],"exampleFix":"// before\nh, err := procid.Open(pid, tok) // procid: pidfd open 4242: too many open files\n// after\nif err != nil && (errors.Is(err, unix.EMFILE) || errors.Is(err, unix.ENFILE)) {\n    runtime.GC() // release fds held by finalizers, close idle conns\n    h, err = procid.Open(pid, tok)\n}","handlingStrategy":"try-catch","validationCode":"// Check kernel support and target liveness before Open\nif _, err := os.Stat(\"/proc/sys/kernel/random/boot_id\"); err != nil { /* env broken */ }\nif err := syscall.Kill(pid, 0); err != nil {\n    if errors.Is(err, unix.ESRCH) { return /* already gone */ }\n}","typeGuard":"func isPidfdOpenFailure(err error) bool {\n    return strings.HasPrefix(err.Error(), \"procid: pidfd open \")\n}","tryCatchPattern":"h, err := procid.Open(pid, tok)\nif err != nil {\n    switch {\n    case errors.Is(err, unix.ESRCH):\n        return // process gone\n    case errors.Is(err, unix.EMFILE), errors.Is(err, unix.ENFILE):\n        // free fds / raise RLIMIT_NOFILE and retry once\n    case errors.Is(err, unix.EPERM):\n        // seccomp blocked pidfd_open: fix container profile or accept fallback\n    }\n    return err\n}","preventionTips":["Raise RLIMIT_NOFILE in services that open many handles","Ensure container seccomp profiles allow pidfd_open (kernel >=5.3, modern runtimes)","Close handles (h.Close()) promptly to avoid fd leaks","Probe with syscall.Kill(pid, 0) before opening a stale PID"],"tags":["linux","pidfd","file-descriptors","kernel"],"backgroundTag":"pidfd-open-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}