{"record":{"id":"b3762467422d7fd9","repo":"openai/codex","slug":"waitpid-failed-for-bubblewrap-child-err","errorCode":null,"errorMessage":"waitpid failed for bubblewrap child: {err}","messagePattern":"waitpid failed for bubblewrap child: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"codex-rs/linux-sandbox/src/linux_run_main.rs","lineNumber":941,"sourceCode":"                let err = std::io::Error::last_os_error();\n                panic!(\"failed to reset bubblewrap signal handler for {signal}: {err}\");\n            }\n        }\n    }\n}\n\nfn wait_for_bwrap_child(pid: libc::pid_t) -> libc::c_int {\n    loop {\n        let mut status: libc::c_int = 0;\n        let wait_res = unsafe { libc::waitpid(pid, &mut status as *mut libc::c_int, 0) };\n        if wait_res >= 0 {\n            return status;\n        }\n        let err = std::io::Error::last_os_error();\n        if err.raw_os_error() == Some(libc::EINTR) {\n            continue;\n        }\n        panic!(\"waitpid failed for bubblewrap child: {err}\");\n    }\n}\n\nfn register_synthetic_mount_targets(\n    targets: &[crate::bwrap::SyntheticMountTarget],\n) -> Vec<SyntheticMountTargetRegistration> {\n    with_synthetic_mount_registry_lock(|| {\n        targets\n            .iter()\n            .map(|target| {\n                let marker_dir = synthetic_mount_marker_dir(target.path());\n                fs::create_dir_all(&marker_dir).unwrap_or_else(|err| {\n                    panic!(\n                        \"failed to create synthetic bubblewrap mount marker directory {}: {err}\",\n                        marker_dir.display()\n                    )\n                });\n                let target = if target.preserves_pre_existing_path()","sourceCodeStart":923,"sourceCodeEnd":959,"githubUrl":"https://github.com/openai/codex/blob/339751715c64496cb86246bfb3935f40e309dd3d/codex-rs/linux-sandbox/src/linux_run_main.rs#L923-L959","documentation":"wait_for_bwrap_child (linux_run_main.rs:930) reaps the forked bwrap child in a loop that retries only EINTR; any other errno panics. For a direct child pid the realistic failure is ECHILD: the child was already reaped elsewhere — a wait-all SIGCHLD handler in the host, another thread calling waitpid(-1), SA_NOCLDWAIT auto-reaping, or a subreaper redirecting the child. The panic aborts the launcher after the sandboxed workload already ran.","triggerScenarios":"Hosting or wrapping the sandbox launcher in a process that globally reaps children while run_bwrap_in_child_with_synthetic_mount_cleanup or run_bwrap_in_child_capture_stderr calls waitpid on its own forked pid.","commonSituations":"Supervisors with wait(-1) loops; runtimes or monitoring agents installing SIGCHLD handlers; SA_NOCLDWAIT set for zombie suppression; test harnesses that fork and reap globally.","solutions":["Remove or scope the global SIGCHLD reaper so each code path reaps only the pids it forked.","Ensure SA_NOCLDWAIT is not set on SIGCHLD while the sandbox runs.","Read the errno in the panic: ECHILD means double reap; EINVAL or anything else means capture a backtrace and report upstream.","Prefer exec'ing the launcher as its own process instead of embedding it in a child-managing supervisor."],"exampleFix":"// before: global reaper steals the sandbox child's status\nunsafe { libc::signal(libc::SIGCHLD, reap_all as libc::sighandler_t); }\n\n// after: no global reaper; only the forking code waits its own pids\n// (delete reap_all entirely, or make it match a specific pid)","handlingStrategy":"validation","validationCode":"fn sigchld_not_auto_reaping() -> bool {\n    let mut current: libc::sigaction = unsafe { std::mem::zeroed() };\n    unsafe { libc::sigaction(libc::SIGCHLD, std::ptr::null(), &mut current) };\n    current.sa_flags & libc::SA_NOCLDWAIT == 0\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never install wait-all SIGCHLD handlers in a process hosting the sandbox launcher.","Always wait on the exact pid you forked; do not reap foreign children.","Run the launcher as a standalone process when a supervisor must manage other children."],"tags":["sandbox","waitpid","sigchld","child-process","double-reap","linux"],"backgroundTag":"waitpid-echild","analyzedSha":"339751715c64496cb86246bfb3935f40e309dd3d","analyzedAt":"2026-08-25T05:35:09.876Z","schemaVersion":2},"datasetVersion":"2026-08-25T06:17:31.827Z"}