{"record":{"id":"8d9407167eadb3fd","repo":"openai/codex","slug":"invalid-http-header-0","errorCode":null,"errorMessage":"invalid HTTP header: {0}","messagePattern":"invalid HTTP header: (.+?)","errorType":"validation","errorClass":"StreamableHttpClientAdapterError","httpStatus":null,"severity":"error","filePath":"codex-rs/rmcp-client/src/http_client_adapter.rs","lineNumber":110,"sourceCode":"    cancellations: Arc<Mutex<HashMap<RequestId, oneshot::Sender<()>>>>,\n}\n\nimpl Drop for EventStreamCancellation {\n    fn drop(&mut self) {\n        self.cancellations\n            .lock()\n            .unwrap_or_else(PoisonError::into_inner)\n            .remove(&self.request_id);\n    }\n}\n\n#[derive(Debug, thiserror::Error)]\npub(crate) enum StreamableHttpClientAdapterError {\n    #[error(\"streamable HTTP session expired with 404 Not Found\")]\n    SessionExpired404,\n    #[error(transparent)]\n    HttpRequest(#[from] ExecServerError),\n    #[error(\"invalid HTTP header: {0}\")]\n    Header(String),\n    #[error(\"MCP response body exceeds {maximum_bytes} bytes\")]\n    ResponseTooLarge { maximum_bytes: usize },\n}\n\nimpl StreamableHttpClientAdapter {\n    pub(crate) fn new(\n        http_client: Arc<dyn HttpClient>,\n        default_headers: HeaderMap,\n        auth_provider: Option<SharedAuthProvider>,\n        has_configured_headers: bool,\n        redirect_mode: StreamableHttpRedirectMode,\n        initialize_deadline: Arc<Mutex<Option<Instant>>>,\n    ) -> Self {\n        Self {\n            http_client: Arc::new(SameOriginRedirectHttpClient::new(http_client)),\n            default_headers,\n            auth_provider,","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/openai/codex/blob/339751715c64496cb86246bfb3935f40e309dd3d/codex-rs/rmcp-client/src/http_client_adapter.rs#L92-L128","documentation":"Header(String) wraps a failure to build an http::HeaderValue for headers the adapter must construct itself: Accept, Content-Type, Authorization: Bearer <token>, Mcp-Session-Id, and Last-Event-Id (all set through insert_header). HeaderValue::from_str rejects anything outside visible ASCII plus space/tab — control bytes, CR/LF, DEL, non-ASCII — so the culprit is almost always a token or session id carrying a stray newline or invisible character.","triggerScenarios":"An auth token containing \\n or other control bytes when rmcp passes it to post_message/get_stream/delete_session; an Mcp-Session-Id or Last-Event-Id returned by a server containing spaces, non-ASCII, or control characters.","commonSituations":"Secrets read from files or env vars with trailing newlines (the classic $(cat token.txt) mistake); tokens copy-pasted with invisible Unicode; a misbehaving server issuing session ids with unusual bytes; values interpolated from unvalidated config.","solutions":["trim() tokens/session ids before passing them to the client","Validate the value is visible-ASCII (bytes 0x20–0x7E plus tab) before the call","If a server-issued id is the culprit, capture it exactly as the server sent it and report the server bug","Add a unit test asserting your token source never contains \\r or \\n"],"exampleFix":"// before\nlet token = std::fs::read_to_string(\"token.txt\")?; // trailing '\\n' -> invalid HTTP header\n\n// after\nlet token = std::fs::read_to_string(\"token.txt\")?.trim().to_string();\nassert!(token.bytes().all(|b| b == b'\\t' || (0x20..0x7f).contains(&b)));","handlingStrategy":"validation","validationCode":"fn assert_header_value_safe(value: &str) {\n    assert!(\n        value.bytes().all(|b| b == b'\\t' || (0x20..0x7f).contains(&b)),\n        \"value contains bytes invalid in an HTTP header\"\n    );\n}\n// apply to every token/session id before handing it to the client\nlet token = token.trim();\nassert_header_value_safe(&token);","typeGuard":"fn is_valid_header_value(value: &str) -> bool {\n    value.bytes().all(|b| b == b'\\t' || (0x20..0x7f).contains(&b))\n}","tryCatchPattern":"// When the client error surfaces:\nif let Some(source) = find_header_error(&error) {\n    // strip and re-validate the offending token/session id, then retry once\n}","preventionTips":["Always trim() secrets read from files or env vars","Never build Authorization values from unvalidated user input","Add tests asserting token sources contain no \\r/\\n","Store session ids opaquely; do not round-trip them through lossy encodings"],"tags":["rust","mcp","http-headers","header-value","invalid-characters"],"backgroundTag":"invalid-http-header-value","analyzedSha":"339751715c64496cb86246bfb3935f40e309dd3d","analyzedAt":"2026-08-25T05:35:09.876Z","schemaVersion":2},"datasetVersion":"2026-08-25T06:17:31.827Z"}