{"record":{"id":"0e8448240da16149","repo":"openai/codex","slug":"mcp-http-headers-helper-must-output-a-json-object","errorCode":null,"errorMessage":"MCP HTTP headers helper must output a JSON object of strings","messagePattern":"MCP HTTP headers helper must output a JSON object of strings","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"codex-rs/rmcp-client/src/http_headers.rs","lineNumber":357,"sourceCode":"        }\n        Ok(output)\n    })\n    .await\n    .map_err(|_| anyhow!(\"MCP HTTP headers helper timed out after 10 seconds\"))??;\n\n    parse_helper_output(output)\n}\n\nfn 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\"","sourceCodeStart":339,"sourceCodeEnd":375,"githubUrl":"https://github.com/openai/codex/blob/339751715c64496cb86246bfb3935f40e309dd3d/codex-rs/rmcp-client/src/http_headers.rs#L339-L375","documentation":"After UTF-8 decoding, stdout must deserialize into a JSON object whose keys and values are all strings, as a single document with nothing after it (deserializer.end() rejects trailing tokens). Arrays, nested objects, numeric/boolean values, or extra text all fail here. The error does not echo the output, so malformed content with embedded secrets is not leaked.","triggerScenarios":"Helper output like [\"a\"], {\"h\": {\"v\": 1}}, {\"n\": 5}, a JSON object followed by extra text, multiple concatenated JSON documents, or JSONL lines.","commonSituations":"Helpers returning structured credential envelopes (nested tokens); scripts printing a banner before or after the JSON; tools emitting several JSON objects; YAML or pretty-printed non-JSON output.","solutions":["Emit exactly one flat JSON object: {\"Header-Name\": \"value\", ...}","Quote every value (numbers included) and keep values as strings","Strip banners/debug lines so stdout contains only the JSON object","Validate shape with jq before wiring the helper in: jq -e 'type == \"object\"' "],"exampleFix":"# before\n{\"X-Trace-Id\": 123, \"X-Org\": {\"id\": 7}}\n\n# after\n{\"X-Trace-Id\": \"123\", \"X-Org-Id\": \"7\"}","handlingStrategy":"validation","validationCode":"# Assert the exact contract: one JSON object, all values strings\ncd \"$MCP_CWD\" && env -i PATH=/usr/bin:/bin sh -c \"$HTTP_HEADERS_HELPER\" | jq -e \\\n  'type == \"object\" and ([to_entries[].value | type] | all(. == \"string\"))' >/dev/null \\\n  && echo shape-ok || echo bad-shape","typeGuard":"fn is_helper_bad_json_shape(error: &anyhow::Error) -> bool {\n    error.to_string().contains(\"must output a JSON object of strings\")\n}","tryCatchPattern":null,"preventionTips":["Print exactly one flat JSON object; quote all values","No banners, no extra lines, no JSONL on stdout","Validate helper output with jq in CI"],"tags":["rust","mcp","headers-helper","json","shape-validation"],"backgroundTag":"invalid-json-output","analyzedSha":"339751715c64496cb86246bfb3935f40e309dd3d","analyzedAt":"2026-08-25T05:35:09.876Z","schemaVersion":2},"datasetVersion":"2026-08-25T06:17:31.827Z"}