openai/codex · error
failed to create bubblewrap exec start pipe: {err}
Error message
failed to create bubblewrap exec start pipe: {err} What it means
When protected-create targets are present, the parent creates an O_CLOEXEC pipe (create_exec_start_pipe, linux_run_main.rs:753) that gates the child: bwrap only execs after wait_for_parent_exec_start sees the parent's byte, written once signal forwarders and the protected-create monitor are armed. pipe2 failing is almost always EMFILE (RLIMIT_NOFILE reached) or ENFILE (system-wide fd table full); the panic aborts the run before fork.
Source
Thrown at codex-rs/linux-sandbox/src/linux_run_main.rs:760
}
}
impl Drop for ProtectedCreateWatcher {
fn drop(&mut self) {
unsafe {
libc::close(self.fd);
}
}
}
fn create_exec_start_pipe(enabled: bool) -> [libc::c_int; 2] {
if !enabled {
return [-1, -1];
}
let mut pipe = [-1, -1];
if unsafe { libc::pipe2(pipe.as_mut_ptr(), libc::O_CLOEXEC) } < 0 {
let err = std::io::Error::last_os_error();
panic!("failed to create bubblewrap exec start pipe: {err}");
}
pipe
}
fn wait_for_parent_exec_start(read_fd: libc::c_int, write_fd: libc::c_int) {
if write_fd >= 0 {
unsafe {
libc::close(write_fd);
}
}
if read_fd < 0 {
return;
}
let mut byte = [0_u8; 1];
loop {
let read = unsafe { libc::read(read_fd, byte.as_mut_ptr().cast(), byte.len()) };
if read >= 0 {View on GitHub (pinned to 339751715c)
Solutions
- Raise the fd limit before launching: ulimit -n 65536 (or LimitNOFILE=65536 in the service unit).
- Inspect /proc/<pid>/fd to find and fix descriptor leaks.
- Reduce the number of concurrent sandboxed sessions in one process.
- If the errno is ENFILE, find the system-wide fd hog (lsof) and restart it.
Example fix
// before: launching with the inherited low limit
run_sandboxed(cmd);
// after: raise RLIMIT_NOFILE to the hard limit first
unsafe {
let mut lim: libc::rlimit = std::mem::zeroed();
libc::getrlimit(libc::RLIMIT_NOFILE, &mut lim);
lim.rlim_cur = lim.rlim_max;
libc::setrlimit(libc::RLIMIT_NOFILE, &lim);
}
run_sandboxed(cmd); Defensive patterns
Strategy: validation
Validate before calling
fn fd_headroom(min_free: usize) -> bool {
let used = std::fs::read_dir("/proc/self/fd").map(|d| d.count()).unwrap_or(usize::MAX);
let mut lim: libc::rlimit = unsafe { std::mem::zeroed() };
unsafe { libc::getrlimit(libc::RLIMIT_NOFILE, &mut lim) };
(lim.rlim_cur as usize).saturating_sub(used) >= min_free
} Prevention
- Set a generous RLIMIT_NOFILE in service definitions and CI shells.
- Track /proc/<pid>/fd growth to catch leaks before EMFILE.
- Bound the number of concurrent sandboxed sessions per process.
When it happens
Trigger: Running a sandboxed command that includes protected_create_targets (the pipe is created only when they are non-empty, linux_run_main.rs:579) from a process at its fd ceiling: leaked descriptors, many concurrent sessions, or a low soft limit (ulimit -n 256/1024).
Common situations: CI shells and systemd services with default LimitNOFILE=1024; long-lived processes leaking sockets or files; heavy parallel sandboxed sessions each holding pipes.
Related errors
- failed to open bundled bubblewrap {}: {err}
- failed to exec bundled bubblewrap {} via {fd_path}: {err}
- failed to read fd flags for preserved bubblewrap file descri
- failed to place bubblewrap child in its own process group: {
- failed to create synthetic bubblewrap mount marker directory
AI-assisted analysis of openai/codex@339751715c (2026-08-25).
Data as JSON: /api/errors/b5e65b2d78da4617.
Report an issue: GitHub.