{"record":{"id":"474a567d7efc1225","repo":"openai/codex","slug":"mcp-http-headers-helper-returned-an-invalid-header","errorCode":null,"errorMessage":"MCP HTTP headers helper returned an invalid header name","messagePattern":"MCP HTTP headers helper returned an invalid header name","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"codex-rs/rmcp-client/src/http_headers.rs","lineNumber":366,"sourceCode":"fn parse_helper_output(stdout: Vec<u8>) -> Result<HeaderMap> {\n    let stdout = String::from_utf8(stdout)\n        .map_err(|_| anyhow!(\"MCP HTTP headers helper wrote non-UTF-8 data\"))?;\n    let mut deserializer = serde_json::Deserializer::from_str(stdout.trim());\n    let headers = RawHeaderEntries::deserialize(&mut deserializer)\n        .and_then(|headers| {\n            deserializer.end()?;\n            Ok(headers)\n        })\n        .map_err(|_| anyhow!(\"MCP HTTP headers helper must output a JSON object of strings\"))?;\n    if headers.has_exact_duplicate {\n        return Err(anyhow!(\n            \"MCP HTTP headers helper returned duplicate header names\"\n        ));\n    }\n    let mut parsed = HeaderMap::with_capacity(headers.entries.len());\n    for (name, value) in headers.entries {\n        let name = HeaderName::from_bytes(name.as_bytes())\n            .map_err(|_| anyhow!(\"MCP HTTP headers helper returned an invalid header name\"))?;\n        // Helper values replace same-name configured headers; bearer/OAuth owns Authorization.\n        // Google IAP uses Proxy-Authorization alongside application Authorization. For HTTPS MCP\n        // URLs it is sent through the forward-proxy tunnel to IAP, not used as CONNECT auth.\n        if matches!(\n            name.as_str(),\n            \"accept\"\n                | \"authorization\"\n                | \"connection\"\n                | \"content-encoding\"\n                | \"content-length\"\n                | \"content-type\"\n                | \"host\"\n                | \"keep-alive\"\n                | \"last-event-id\"\n                | \"mcp-protocol-version\"\n                | \"mcp-session-id\"\n                | \"origin\"\n                | \"proxy-connection\"","sourceCodeStart":348,"sourceCodeEnd":384,"githubUrl":"https://github.com/openai/codex/blob/339751715c64496cb86246bfb3935f40e309dd3d/codex-rs/rmcp-client/src/http_headers.rs#L348-L384","documentation":"Each key in the helper's JSON must be a valid HTTP header name per HeaderName::from_bytes: ASCII token characters — letters, digits, and !#$%&'*+-.^_`|~ — with no spaces, colons, CR/LF, or non-ASCII bytes. Output like a full header line (\"Authorization: Bearer x\") used as the key, or a name with a space, fails here before the reserved-header check.","triggerScenarios":"Helper emitting full 'Name: value' lines wrapped as keys, header names containing spaces or non-token characters, trailing colons, or non-ASCII names (e.g. accented organization names).","commonSituations":"Scripts that echo raw HTTP header lines and naively wrap them in JSON; copy-pasted names with trailing colons; Unicode names from internal systems; keys built by string concatenation without token validation.","solutions":["Emit only the header name as the key — no colon, no value, no trailing space","Restrict names to letters, digits, and hyphens (safest subset of token chars)","Validate with a token regex before printing: ^[!#$%&'*+.^_`|~0-9A-Za-z]+$","If the name came from a parsed header line, split on the first colon and trim"],"exampleFix":"# before\n{\"Authorization: Bearer x\": \"unused\"}\n\n# after\n{\"X-Api-Key\": \"...\"}","handlingStrategy":"validation","validationCode":"# Every key must be a valid HTTP token name\ncd \"$MCP_CWD\" && env -i PATH=/usr/bin:/bin sh -c \"$HTTP_HEADERS_HELPER\" \\\n  | jq -r 'keys[]' | grep -Ev \"^[!#\\$%&'*+.^_`|~0-9A-Za-z]+$\" \\\n  && echo invalid-header-name || echo names-ok","typeGuard":"fn is_valid_header_name(name: &str) -> bool {\n    !name.is_empty()\n        && name.bytes().all(|b| b.is_ascii_alphanumeric() || b![!#$%&'*+.^_`|~].contains(&b))\n}","tryCatchPattern":null,"preventionTips":["Emit bare header names as keys — never full 'Name: value' lines","Restrict names to letters/digits/hyphens for portability","Split parsed header lines on the first colon and trim before emitting"],"tags":["rust","mcp","headers-helper","header-name","invalid-token"],"backgroundTag":"invalid-http-header-name","analyzedSha":"339751715c64496cb86246bfb3935f40e309dd3d","analyzedAt":"2026-08-25T05:35:09.876Z","schemaVersion":2},"datasetVersion":"2026-08-25T06:17:31.827Z"}