openai/codex · error

MCP HTTP headers helper process id was unavailable

Error message

MCP HTTP headers helper process id was unavailable

What it means

On Unix the helper records the child pid so the whole process group can be killed on drop; tokio's Child::id() returns None only after the child has already exited and been reaped. This error means the helper died so fast the pid was gone before it could be captured — effectively an instant-exit spawn, and the error text avoids echoing anything the command printed.

Source

Thrown at codex-rs/rmcp-client/src/http_headers.rs:315

    #[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,
    };
    let output = tokio::time::timeout(HELPER_TIMEOUT, async {
        let stdout = process
            .child
            .stdout
            .take()
            .ok_or_else(|| anyhow!("MCP HTTP headers helper stdout was unavailable"))?;
        let mut output = Vec::new();
        stdout
            .take((MAX_HELPER_OUTPUT_BYTES + 1) as u64)
            .read_to_end(&mut output)
            .await?;
        if output.len() > MAX_HELPER_OUTPUT_BYTES {
            return Err(anyhow!("MCP HTTP headers helper output exceeds 64 KiB"));
        }

View on GitHub (pinned to 339751715c)

Solutions

  1. Make sure the command actually runs a program that prints the JSON headers object
  2. Validate the command is non-empty and syntactically valid (sh -n -c '<command>') before configuring
  3. Fix the command as you would for a spawn failure — the process vanished on start

Example fix

# before
httpHeadersHelper = ""   # exits instantly, pid already reaped

# after
httpHeadersHelper = "/usr/local/bin/my-auth-helper --json"
Defensive patterns

Strategy: try-catch

Validate before calling

# Reject empty or syntactically invalid helper commands before configuring
[ -n "$HTTP_HEADERS_HELPER" ] || { echo 'helper command is empty'; exit 1; }
sh -n -c "$HTTP_HEADERS_HELPER" || echo 'helper command is not valid sh'

Type guard

fn is_helper_pid_unavailable(error: &anyhow::Error) -> bool {
    error.to_string().contains("process id was unavailable")
}

Try / catch

// instant-exit spawn: fix the command, nothing to retry
if let Err(error) = provider.headers().await {
    if error.to_string().contains("process id was unavailable") {
        // treat exactly like 'failed to start': correct or empty the command
    }
}

Prevention

When it happens

Trigger: A headers-helper command that exits immediately (empty or whitespace command, 'exit', a comment-only line, exec failure detected by sh), letting the runtime reap the child before id() is read.

Common situations: Empty or unset httpHeadersHelper value slipping through config validation; command strings that are only comments or shell builtins; command line whose first token is an empty string.

Related errors


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