{"record":{"id":"bc8aded351de543f","repo":"openai/codex","slug":"mcp-http-headers-helper-process-id-was-unavailable","errorCode":null,"errorMessage":"MCP HTTP headers helper process id was unavailable","messagePattern":"MCP HTTP headers helper process id was unavailable","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"codex-rs/rmcp-client/src/http_headers.rs","lineNumber":315,"sourceCode":"\n    #[cfg(windows)]\n    let (child, job) = {\n        let job = codex_utils_pty::JobObject::create_without_breakaway()\n            .map_err(|error| anyhow!(\"MCP HTTP headers helper containment failed: {error}\"))?;\n        let child = job\n            .spawn_contained(&mut process)\n            .map_err(|error| anyhow!(\"MCP HTTP headers helper failed to start: {error}\"))?;\n        (child, job)\n    };\n    #[cfg(not(windows))]\n    let child = process\n        .spawn()\n        .map_err(|error| anyhow!(\"MCP HTTP headers helper failed to start: {error}\"))?;\n    let mut process = HelperProcess {\n        #[cfg(unix)]\n        process_group_id: child\n            .id()\n            .ok_or_else(|| anyhow!(\"MCP HTTP headers helper process id was unavailable\"))?,\n        child,\n        #[cfg(windows)]\n        job,\n    };\n    let output = tokio::time::timeout(HELPER_TIMEOUT, async {\n        let stdout = process\n            .child\n            .stdout\n            .take()\n            .ok_or_else(|| anyhow!(\"MCP HTTP headers helper stdout was unavailable\"))?;\n        let mut output = Vec::new();\n        stdout\n            .take((MAX_HELPER_OUTPUT_BYTES + 1) as u64)\n            .read_to_end(&mut output)\n            .await?;\n        if output.len() > MAX_HELPER_OUTPUT_BYTES {\n            return Err(anyhow!(\"MCP HTTP headers helper output exceeds 64 KiB\"));\n        }","sourceCodeStart":297,"sourceCodeEnd":333,"githubUrl":"https://github.com/openai/codex/blob/339751715c64496cb86246bfb3935f40e309dd3d/codex-rs/rmcp-client/src/http_headers.rs#L297-L333","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Make sure the command actually runs a program that prints the JSON headers object","Validate the command is non-empty and syntactically valid (sh -n -c '<command>') before configuring","Fix the command as you would for a spawn failure — the process vanished on start"],"exampleFix":"# before\nhttpHeadersHelper = \"\"   # exits instantly, pid already reaped\n\n# after\nhttpHeadersHelper = \"/usr/local/bin/my-auth-helper --json\"","handlingStrategy":"try-catch","validationCode":"# Reject empty or syntactically invalid helper commands before configuring\n[ -n \"$HTTP_HEADERS_HELPER\" ] || { echo 'helper command is empty'; exit 1; }\nsh -n -c \"$HTTP_HEADERS_HELPER\" || echo 'helper command is not valid sh'","typeGuard":"fn is_helper_pid_unavailable(error: &anyhow::Error) -> bool {\n    error.to_string().contains(\"process id was unavailable\")\n}","tryCatchPattern":"// instant-exit spawn: fix the command, nothing to retry\nif let Err(error) = provider.headers().await {\n    if error.to_string().contains(\"process id was unavailable\") {\n        // treat exactly like 'failed to start': correct or empty the command\n    }\n}","preventionTips":["Reject empty helper commands in config validation","Test the helper runs and prints JSON before enabling it","Treat pid-unavailable as a spawn failure, not a transient race"],"tags":["rust","mcp","unix","process-exit","race","headers-helper"],"backgroundTag":"process-spawn-failed","analyzedSha":"339751715c64496cb86246bfb3935f40e309dd3d","analyzedAt":"2026-08-25T05:35:09.876Z","schemaVersion":2},"datasetVersion":"2026-08-25T06:17:31.827Z"}