openai/codex · error · anyhow::Error
MCP HTTP headers helper containment failed: {error}
Error message
MCP HTTP headers helper containment failed: {error} What it means
On Windows, the MCP HTTP headers helper (a shell command that prints auth headers as JSON) is spawned inside a Job Object created with create_without_breakaway so it cannot escape containment. If Windows refuses to create the Job Object, setup aborts before the command even runs, and this error wraps the underlying OS failure. It is an OS-level containment problem, not a problem with the configured helper command.
Source
Thrown at codex-rs/rmcp-client/src/http_headers.rs:301
}
#[cfg(not(windows))]
process.args(["-c", command]);
#[cfg(unix)]
process.process_group(0);
process
.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::null())
.current_dir(cwd)
// Match local MCP subprocess policy; arbitrary ambient variables are not inherited.
.env_clear()
.envs(create_env_for_mcp_server(/*extra_env*/ None, &[])?)
.kill_on_drop(true);
#[cfg(windows)]
let (child, job) = {
let job = codex_utils_pty::JobObject::create_without_breakaway()
.map_err(|error| anyhow!("MCP HTTP headers helper containment failed: {error}"))?;
let child = job
.spawn_contained(&mut process)
.map_err(|error| anyhow!("MCP HTTP headers helper failed to start: {error}"))?;
(child, job)
};
#[cfg(not(windows))]
let child = process
.spawn()
.map_err(|error| anyhow!("MCP HTTP headers helper failed to start: {error}"))?;
let mut process = HelperProcess {
#[cfg(unix)]
process_group_id: child
.id()
.ok_or_else(|| anyhow!("MCP HTTP headers helper process id was unavailable"))?,
child,
#[cfg(windows)]
job,
};View on GitHub (pinned to 339751715c)
Solutions
- Run the orchestrator outside the restricted job/sandbox that denies Job Object creation
- Check and reduce process/handle counts (Task Manager, Sysinternals) if exhaustion is suspected
- Reproduce with a minimal CreateJobObject call on the same host to confirm the OS restriction
- If self-hosting in containers, use a Windows host configuration that permits job objects
Defensive patterns
Strategy: try-catch
Type guard
fn is_containment_failure(error: &anyhow::Error) -> bool {
error.to_string().contains("containment failed")
} Try / catch
if let Err(error) = connect_mcp_with_headers_helper(&config).await {
if error.to_string().contains("containment failed") {
// Windows job-object restriction on this host: rerun outside the
// restricted job/sandbox; not a config bug
return Err(error.context("host restricts Job Objects; use an unrestricted Windows host"));
}
return Err(error);
} Prevention
- Avoid running the orchestrator inside nested/breakaway-denying jobs on Windows
- Monitor handle/process counts on long-lived Windows hosts
- Include a Job Object smoke test in Windows CI for helper-based MCP configs
When it happens
Trigger: Configuring an MCP HTTP server with a headers-helper command on Windows when CreateJobObject fails — kernel object/handle exhaustion, an existing job that denies child job creation without breakaway, or a hardened/sandboxed host restricting job objects.
Common situations: CI runners or restricted Windows hosts with job-object limits; processes already nested inside breakaway-denying jobs; handle leaks from long-running orchestrators exhausting the object table.
Related errors
- MCP HTTP headers helper failed to start: {error}
- MCP HTTP headers helper process id was unavailable
- MCP HTTP headers helper stdout was unavailable
- MCP HTTP headers helper exited with status {status}
- MCP HTTP headers helper wrote non-UTF-8 data
AI-assisted analysis of openai/codex@339751715c (2026-08-25).
Data as JSON: /api/errors/c7c69acecd0ae32f.
Report an issue: GitHub.