{"record":{"id":"d1aada0d49fb82b6","repo":"rust-lang/rust","slug":"pidfd-spawnp-succeeded-but-the-child-s-pid-could-n","errorCode":null,"errorMessage":"pidfd_spawnp succeeded but the child's PID could not be obtained","messagePattern":"pidfd_spawnp succeeded but the child's PID could not be obtained","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"library/std/src/sys/process/unix/unix.rs","lineNumber":810,"sourceCode":"                    && e.raw_os_error() == Some(libc::ENOSYS)\n                {\n                    PIDFD_SUPPORTED.store(FORK_EXEC, Ordering::Relaxed);\n                    return Ok(None);\n                }\n                spawn_res?;\n\n                use crate::os::fd::{FromRawFd, IntoRawFd};\n\n                let pidfd = PidFd::from_raw_fd(pidfd);\n                let pid = match pidfd.pid() {\n                    Ok(pid) => pid,\n                    Err(e) => {\n                        // The child has been spawned and we are holding its pidfd.\n                        // But we cannot obtain its pid even though pidfd_spawnp and getpid support\n                        // was verified earlier.\n                        // This is quite unlikely, but might happen if the ioctl is not supported,\n                        // glibc tries to use procfs and we're out of file descriptors.\n                        return Err(Error::new(\n                            e.kind(),\n                            \"pidfd_spawnp succeeded but the child's PID could not be obtained\",\n                        ));\n                    }\n                };\n\n                return Ok(Some(Process::new(pid as i32, pidfd.into_raw_fd())));\n            }\n\n            // Safety: -1 indicates we don't have a pidfd.\n            let mut p = Process::new(0, -1);\n\n            let spawn_res = spawn_fn(\n                &mut p.pid,\n                self.get_program_cstr().as_ptr(),\n                file_actions.0.as_ptr(),\n                attrs.0.as_ptr(),\n                self.get_argv().as_ptr() as *const _,","sourceCodeStart":792,"sourceCodeEnd":828,"githubUrl":"https://github.com/rust-lang/rust/blob/7088e4b63a9516ebfbfe2ab2d999cf01a528ac14/library/std/src/sys/process/unix/unix.rs#L792-L828","documentation":"Returned by Rust std's Linux pidfd-spawn path after pidfd_spawnp succeeds but the subsequent pidfd.pid() call fails. The child has already been spawned and std holds its pidfd, yet it cannot read the PID - typically because the PID-fetching ioctl is unsupported, glibc's procfs fallback is blocked, or the process is out of file descriptors. The original error kind is preserved and wrapped with this explanatory message.","triggerScenarios":"Spawning a child with Command and .create_pidfd(true) on a Linux kernel/glibc combination where pidfd_spawnp works but pidfd_getfd/pid retrieval does not - e.g. restricted seccomp filter blocking /proc, procfs unmounted, or EMFILE (out of fds). The fallback at PIDFD_SUPPORTED already ruled out ENOSYS, so this is a post-spawn inconsistency.","commonSituations":"Containerized runtime with procfs masked/read-only; seccomp profile missing the ioctl syscalls; very high fd usage hitting RLIMIT_NOFILE; older glibc advertising pidfd_spawnp but buggy pid query.","solutions":["Disable create_pidfd on the Command to fall back to fork+exec, which returns the PID directly.","Ensure procfs is mounted and readable at /proc in the sandbox/container.","Loosen the seccomp filter to allow the pidfd-related ioctls, or raise RLIMIT_NOFILE.","Upgrade glibc to a version with a correct pidfd pid retrieval implementation."],"exampleFix":"// before\nlet mut cmd = Command::new(\"./child\");\ncmd.create_pidfd(true);\nlet child = cmd.spawn()?;\n\n// after\nlet mut cmd = Command::new(\"./child\");\n// do not request a pidfd; rely on fork+exec\nlet child = cmd.spawn()?;","handlingStrategy":"fallback","validationCode":"// Disable pidfd when running in restricted sandboxes.\nfn wants_pidfd() -> bool {\n    std::env::var_os(\"SANDBOX\").is_none() && std::fs::metadata(\"/proc/self\").is_ok()\n}\n// if !wants_pidfd() { cmd.create_pidfd(false); }","typeGuard":null,"tryCatchPattern":"let mut cmd = Command::new(prog);\ncmd.create_pidfd(true);\nmatch cmd.spawn() {\n    Ok(child) => Ok(child),\n    Err(e) if e.to_string().contains(\"PID could not be obtained\") => {\n        let mut cmd2 = Command::new(prog); // no pidfd\n        cmd2.spawn()\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Do not request pidfd in containers that mask /proc or restrict ioctls.","Ensure procfs is mounted and RLIMIT_NOFILE is adequate.","Fall back to fork+exec by disabling create_pidfd on spawn errors."],"tags":["rust","std","process","linux","pidfd","spawn","syscall"],"backgroundTag":null,"analyzedSha":"7088e4b63a9516ebfbfe2ab2d999cf01a528ac14","analyzedAt":"2026-08-10T14:17:03.603Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}