{"record":{"id":"472a9445885a7903","repo":"Hmbown/CodeWhale","slug":"duplicate-lsp-content-length","errorCode":null,"errorMessage":"duplicate LSP Content-Length","messagePattern":"duplicate LSP Content-Length","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/lsp/client.rs","lineNumber":602,"sourceCode":"/// Distinguish incomplete headers from malformed or oversized frames so a\n/// broken server cannot cause an indefinitely growing input buffer.\nfn parse_header(buf: &[u8]) -> Result<Option<(usize, usize)>> {\n    let Some(pos) = buf.windows(4).position(|window| window == b\"\\r\\n\\r\\n\") else {\n        if buf.len() > MAX_LSP_HEADER_BYTES {\n            return Err(anyhow!(\"LSP header exceeds size limit\"));\n        }\n        return Ok(None);\n    };\n    if pos + 4 > MAX_LSP_HEADER_BYTES {\n        return Err(anyhow!(\"LSP header exceeds size limit\"));\n    }\n    let header = std::str::from_utf8(&buf[..pos]).context(\"invalid LSP header encoding\")?;\n    let mut content_length = None;\n    for line in header.split(\"\\r\\n\") {\n        let (name, value) = line.split_once(':').context(\"malformed LSP header\")?;\n        if name.eq_ignore_ascii_case(\"Content-Length\") {\n            if content_length.is_some() {\n                return Err(anyhow!(\"duplicate LSP Content-Length\"));\n            }\n            let length = value\n                .trim()\n                .parse::<usize>()\n                .context(\"invalid LSP Content-Length\")?;\n            if length == 0 || length > MAX_LSP_FRAME_BYTES {\n                return Err(anyhow!(\"LSP frame exceeds size limit or is empty\"));\n            }\n            content_length = Some(length);\n        }\n    }\n    Ok(Some((\n        pos + 4,\n        content_length.context(\"missing LSP Content-Length\")?,\n    )))\n}\n\n/// Background task that consumes inbound JSON values, classifies them as","sourceCodeStart":584,"sourceCodeEnd":620,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/lsp/client.rs#L584-L620","documentation":"LSP headers must contain at most one Content-Length field. When parse_header iterates the header lines and finds a second Content-Length, it cannot unambiguously determine the frame size and rejects the message. This protects against ambiguous framing from a non-conformant server.","triggerScenarios":"Server sends a message whose header block contains two Content-Length lines (e.g. duplicated by a buggy proxy, a hand-rolled client/server implementation, or concatenated malformed frames).","commonSituations":"Custom LSP middleware that re-writes headers without removing the original, hand-written test doubles emitting both `Content-Length` and `content-length` (eq_ignore_ascii_case makes them collide), or frame concatenation bugs where two headers end up in one block.","solutions":["Fix or remove the intermediary that duplicates the header.","Check the server implementation: emit exactly one Content-Length per message.","Capture the raw stream (tee stdout) and confirm the duplicate, then fix the producer.","If writing your own LSP peer, reuse a battle-tested framing library instead of hand-rolling headers."],"exampleFix":"// before (hand-rolled sender)\nlet header = \"Content-Length: 42\\r\\nContent-Length: 42\\r\\n\\r\\n\";\n// after\nlet header = format!(\"Content-Length: {}\\r\\n\\r\\n\", body.len());","handlingStrategy":"validation","validationCode":"// when acting as an LSP peer, assert exactly one Content-Length per frame\nlet count = header.lines().filter(|l| l.to_ascii_lowercase().starts_with(\"content-length:\")).count();\nassert_eq!(count, 1, \"duplicate Content-Length in outgoing header\");","typeGuard":null,"tryCatchPattern":"match parse_result {\n    Err(e) if e.to_string().contains(\"duplicate LSP Content-Length\") => {\n        report_broken_peer();\n        disconnect_and_restart().await\n    }\n    other => other,\n}","preventionTips":["Never hand-roll LSP headers; use a framing helper/library","Test custom middleware for header rewriting","Watch for case-variant duplicates (Content-Length vs content-length)","Add a protocol conformance test to any in-house LSP server"],"tags":["lsp","protocol","malformed-header","framing"],"backgroundTag":"unexpected-response-shape","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T16:17:23.217Z"}