{"record":{"id":"19bba02942511c1b","repo":"Hmbown/CodeWhale","slug":"lsp-frame-exceeds-size-limit-or-is-empty","errorCode":null,"errorMessage":"LSP frame exceeds size limit or is empty","messagePattern":"LSP frame exceeds size limit or is empty","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/lsp/client.rs","lineNumber":609,"sourceCode":"        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\n/// notifications/responses, and routes accordingly.\nasync fn dispatcher_task(\n    mut rx: mpsc::Receiver<Value>,\n    tx_diag: mpsc::Sender<DiagnosticMessage>,\n    pending: Arc<AsyncMutex<HashMap<i64, oneshot::Sender<Value>>>>,\n) {\n    while let Some(value) = rx.recv().await {","sourceCodeStart":591,"sourceCodeEnd":627,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/lsp/client.rs#L591-L627","documentation":"After parsing Content-Length, parse_header validates that the declared frame length is non-zero and does not exceed MAX_LSP_FRAME_BYTES. A zero-length body is not a valid LSP message and an oversized body could exhaust memory, so both are rejected before the client allocates the frame buffer.","triggerScenarios":"Server advertises Content-Length: 0, or a Content-Length larger than MAX_LSP_FRAME_BYTES (e.g. a huge/ corrupted value, or an integer overflow/parse artifact like a bogus multi-gigabyte length).","commonSituations":"Buggy server sending keep-alive empty frames, a corrupted length field from binary junk in the stream, a malicious server attempting a memory-exhaustion DoS with an enormous declared length, or a truncation bug producing a zero-length final message.","solutions":["Fix the server so every message has a non-empty JSON-RPC body within the size limit.","Reduce oversized payloads server-side (e.g. huge completion results, massive diagnostics) or raise MAX_LSP_FRAME_BYTES deliberately.","Treat this as a fatal stream error and restart the server connection.","Audit the server for length-computation bugs (off-by-one, byte vs char counts)."],"exampleFix":"// before (server-side)\nlet frame = format!(\"Content-Length: {}\\r\\n\\r\\n\", \"\");\n// after\nif body.is_empty() { return; } // skip empty notifications\nlet frame = format!(\"Content-Length: {}\\r\\n\\r\\n\", body.len());","handlingStrategy":"validation","validationCode":"// validate the declared length before allocating\nfn sane_length(len: usize, max: usize) -> bool { len > 0 && len <= max }","typeGuard":null,"tryCatchPattern":"match client.next_message().await {\n    Err(e) if e.to_string().contains(\"size limit or is empty\") => {\n        // cannot trust declared sizes from this peer; restart\n        restart_server().await?;\n        Err(e)\n    }\n    other => other,\n}","preventionTips":["Reject Content-Length: 0 on the producing side before sending","Split oversized payloads (e.g. huge diagnostics) server-side","Audit length computation for byte-vs-char and overflow bugs","Keep declared sizes bounded; never echo untrusted lengths into allocations"],"tags":["lsp","protocol","payload-size","validation"],"backgroundTag":"payload-too-large","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}