rust-lang/rust · error · io::Error

pidfd_spawnp succeeded but the child's PID could not be obta

Error message

pidfd_spawnp succeeded but the child's PID could not be obtained

What it means

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.

Source

Thrown at library/std/src/sys/process/unix/unix.rs:810

                    && e.raw_os_error() == Some(libc::ENOSYS)
                {
                    PIDFD_SUPPORTED.store(FORK_EXEC, Ordering::Relaxed);
                    return Ok(None);
                }
                spawn_res?;

                use crate::os::fd::{FromRawFd, IntoRawFd};

                let pidfd = PidFd::from_raw_fd(pidfd);
                let pid = match pidfd.pid() {
                    Ok(pid) => pid,
                    Err(e) => {
                        // The child has been spawned and we are holding its pidfd.
                        // But we cannot obtain its pid even though pidfd_spawnp and getpid support
                        // was verified earlier.
                        // This is quite unlikely, but might happen if the ioctl is not supported,
                        // glibc tries to use procfs and we're out of file descriptors.
                        return Err(Error::new(
                            e.kind(),
                            "pidfd_spawnp succeeded but the child's PID could not be obtained",
                        ));
                    }
                };

                return Ok(Some(Process::new(pid as i32, pidfd.into_raw_fd())));
            }

            // Safety: -1 indicates we don't have a pidfd.
            let mut p = Process::new(0, -1);

            let spawn_res = spawn_fn(
                &mut p.pid,
                self.get_program_cstr().as_ptr(),
                file_actions.0.as_ptr(),
                attrs.0.as_ptr(),
                self.get_argv().as_ptr() as *const _,

View on GitHub (pinned to 7088e4b63a)

Solutions

  1. Disable create_pidfd on the Command to fall back to fork+exec, which returns the PID directly.
  2. Ensure procfs is mounted and readable at /proc in the sandbox/container.
  3. Loosen the seccomp filter to allow the pidfd-related ioctls, or raise RLIMIT_NOFILE.
  4. Upgrade glibc to a version with a correct pidfd pid retrieval implementation.

Example fix

// before
let mut cmd = Command::new("./child");
cmd.create_pidfd(true);
let child = cmd.spawn()?;

// after
let mut cmd = Command::new("./child");
// do not request a pidfd; rely on fork+exec
let child = cmd.spawn()?;
Defensive patterns

Strategy: fallback

Validate before calling

// Disable pidfd when running in restricted sandboxes.
fn wants_pidfd() -> bool {
    std::env::var_os("SANDBOX").is_none() && std::fs::metadata("/proc/self").is_ok()
}
// if !wants_pidfd() { cmd.create_pidfd(false); }

Try / catch

let mut cmd = Command::new(prog);
cmd.create_pidfd(true);
match cmd.spawn() {
    Ok(child) => Ok(child),
    Err(e) if e.to_string().contains("PID could not be obtained") => {
        let mut cmd2 = Command::new(prog); // no pidfd
        cmd2.spawn()
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of rust-lang/rust@7088e4b63a (2026-08-10). Data as JSON: /api/errors/d1aada0d49fb82b6. Report an issue: GitHub.