openai/codex · critical
failed to place bubblewrap child in its own process group: {
Error message
failed to place bubblewrap child in its own process group: {err} What it means
The forked child that will exec bubblewrap calls libc::setpgid(0, 0) to move itself into a fresh process group; the parent relies on this to forward signals to the whole sandbox tree via kill(-pid, ...) (send_signal_to_bwrap_child, linux_run_main.rs:912). Linux guarantees setpgid(0,0) succeeds on a just-forked child, so this panic means the environment broke that invariant: an outer seccomp/LSM policy denies setpgid, or an exotic runtime (gVisor, a nested sandbox) restricts process-group changes. The child dies before exec, so every sandboxed run fails.
Source
Thrown at codex-rs/linux-sandbox/src/linux_run_main.rs:593
let setup_signal_mask = ForwardedSignalMask::block();
let synthetic_mount_registrations = register_synthetic_mount_targets(&synthetic_mount_targets);
let protected_create_registrations =
register_protected_create_targets(&protected_create_targets);
let exec_start_pipe = create_exec_start_pipe(!protected_create_targets.is_empty());
let parent_pid = unsafe { libc::getpid() };
let pid = unsafe { libc::fork() };
if pid < 0 {
let err = std::io::Error::last_os_error();
panic!("failed to fork for bubblewrap: {err}");
}
if pid == 0 {
reset_forwarded_signal_handlers_to_default();
setup_signal_mask.restore();
let setpgid_res = unsafe { libc::setpgid(0, 0) };
if setpgid_res < 0 {
let err = std::io::Error::last_os_error();
panic!("failed to place bubblewrap child in its own process group: {err}");
}
terminate_with_parent(parent_pid);
wait_for_parent_exec_start(exec_start_pipe[0], exec_start_pipe[1]);
exec_bwrap(args, preserved_files);
}
close_child_exec_start_read(exec_start_pipe[0]);
let protected_create_monitor = ProtectedCreateMonitor::start(&protected_create_targets);
let signal_forwarders = install_bwrap_signal_forwarders(pid);
release_child_exec_start(exec_start_pipe[1]);
setup_signal_mask.restore();
let status = wait_for_bwrap_child(pid);
let cleanup_signal_mask = ForwardedSignalMask::block();
BWRAP_CHILD_PID.store(0, Ordering::SeqCst);
let protected_create_monitor_violation = protected_create_monitor
.map(ProtectedCreateMonitor::stop)
.unwrap_or(false);
cleanup_synthetic_mount_targets(&synthetic_mount_registrations);View on GitHub (pinned to 339751715c)
Solutions
- Stop nesting sandboxes, or run the launcher outside the restrictive wrapper.
- If you own the outer seccomp policy, allow the setpgid syscall (syscall 109, @process group).
- Reproduce with strace -f -e setpgid to capture the exact errno printed in the panic.
- If the errno is unexpected on a stock kernel, report it against codex-rs/linux-sandbox with the trace.
Example fix
# before: outer unit filters process-management calls SystemCallFilter=~@process # after: allow setpgid for the nested sandbox launcher SystemCallFilter=add setpgid
Defensive patterns
Strategy: validation
Validate before calling
fn process_group_creation_works() -> bool {
match unsafe { libc::fork() } {
0 => unsafe { libc::_exit(if libc::setpgid(0, 0) == 0 { 0 } else { 1 }) },
pid if pid > 0 => {
let mut status = 0;
unsafe { libc::waitpid(pid, &mut status, 0) };
libc::WIFEXITED(status) && libc::WEXITSTATUS(status) == 0
}
_ => false,
}
} Prevention
- Do not run the linux sandbox launcher under a seccomp profile that denies setpgid.
- Add a CI smoke test that executes one trivial sandboxed command to catch environment regressions early.
- Record the errno from the panic message to identify which policy layer denied the syscall.
When it happens
Trigger: Any sandboxed command whose BwrapArgs carry synthetic mount targets or protected-create targets, forcing the fork path in run_or_exec_bwrap (linux_run_main.rs:568-598), executed under a wrapper whose seccomp filter blocks setpgid (EPERM) or denies it through policy.
Common situations: Nesting the linux-sandbox launcher inside another sandbox or container with a restrictive seccomp profile; hardened CI runners; gVisor-based runtimes; kernel hardening modules denying process-group manipulation.
Related errors
- failed to open bundled bubblewrap {}: {err}
- failed to exec bundled bubblewrap {} via {fd_path}: {err}
- invalid bundled bubblewrap fd path: {err}
- failed to normalize bundled bubblewrap path {}: {err}
- failed to read fd flags for preserved bubblewrap file descri
AI-assisted analysis of openai/codex@339751715c (2026-08-25).
Data as JSON: /api/errors/cc212cc451999bf3.
Report an issue: GitHub.