{"record":{"id":"f42ef220f895f359","repo":"Hmbown/CodeWhale","slug":"lsp-header-exceeds-size-limit","errorCode":null,"errorMessage":"LSP header exceeds size limit","messagePattern":"LSP header exceeds size limit","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/lsp/client.rs","lineNumber":589,"sourceCode":"            }\n            let value = match serde_json::from_slice::<Value>(&buf[header_end..frame_end]) {\n                Ok(value) => value,\n                Err(_) => return,\n            };\n            buf.drain(..frame_end);\n            if tx.send(value).await.is_err() {\n                return;\n            }\n        }\n    }\n}\n\n/// 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\")?;","sourceCodeStart":571,"sourceCodeEnd":607,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/lsp/client.rs#L571-L607","documentation":"parse_header scans the inbound byte buffer for the \\r\\n\\r\\n header terminator when no terminator has been found yet. If the accumulated buffer exceeds MAX_LSP_HEADER_BYTES without a terminator, the header can never be valid, so the client errors out. This exists so a broken or malicious LSP server cannot make the input buffer grow indefinitely.","triggerScenarios":"reader_task receives bytes from the server's stdout that never contain \\r\\n\\r\\n within MAX_LSP_HEADER_BYTES; e.g. the server emits binary garbage, raw JSON without an LSP framing header, or a corrupted stream.","commonSituations":"Pointing the client at a server that speaks plain JSON-RPC over stdio without Content-Length framing, a crashed server dumping a stack trace or binary output to stdout, or stdout/stderr wiring mixed up in a wrapper script.","solutions":["Verify the configured LSP server binary actually implements the LSP stdio transport (Content-Length headers) rather than line-delimited JSON.","Check that the server's stdout is clean — redirect debug logging to stderr, not stdout.","Restart the server process; the stream is desynchronized and cannot recover mid-frame.","If the server legitimately sends huge headers, raise MAX_LSP_HEADER_BYTES (with care) or upgrade the server."],"exampleFix":"// before (wrapper script)\nmy-lsp-server --verbose   # logs to stdout\n// after\nmy-lsp-server --verbose 2>server.log   # keep stdout protocol-only","handlingStrategy":"validation","validationCode":"// sanity-check the server speaks LSP framing before wiring it up\nlet probe = std::process::Command::new(&server_bin).arg(\"--version\").output()?;\nif !probe.status.success() { return Err(\"binary is not a working LSP server\"); }","typeGuard":null,"tryCatchPattern":"match reader_result {\n    Err(e) if e.to_string().contains(\"header exceeds size limit\") => {\n        // stream is desynchronized: kill and restart the server\n        server.kill().await.ok();\n        restart_with_framing_check().await\n    }\n    other => other,\n}","preventionTips":["Ensure server logs go to stderr, never stdout","Smoke-test servers with an LSP conformance probe before registering them","Never wrap the server in scripts that echo to stdout","Cap restart loops so a permanently broken server fails fast"],"tags":["lsp","protocol","framing","stream-corruption"],"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"}