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

  1. Run the orchestrator outside the restricted job/sandbox that denies Job Object creation
  2. Check and reduce process/handle counts (Task Manager, Sysinternals) if exhaustion is suspected
  3. Reproduce with a minimal CreateJobObject call on the same host to confirm the OS restriction
  4. 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

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


AI-assisted analysis of openai/codex@339751715c (2026-08-25). Data as JSON: /api/errors/c7c69acecd0ae32f. Report an issue: GitHub.