Hmbown/CodeWhale · error
LSP frame exceeds size limit or is empty
Error message
LSP frame exceeds size limit or is empty
What it means
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.
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).
Example fix
// before (server-side)
let frame = format!("Content-Length: {}\r\n\r\n", "");
// after
if body.is_empty() { return; } // skip empty notifications
let frame = format!("Content-Length: {}\r\n\r\n", body.len()); Defensive patterns
Strategy: validation
Validate before calling
// validate the declared length before allocating
fn sane_length(len: usize, max: usize) -> bool { len > 0 && len <= max } Try / catch
match client.next_message().await {
Err(e) if e.to_string().contains("size limit or is empty") => {
// cannot trust declared sizes from this peer; restart
restart_server().await?;
Err(e)
}
other => other,
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Understand the failure class
Background: payload too large / request exceeds maximum size: why libraries cap bytes and how to fix oversize payloads — this error's family across 50 libraries.
Related errors
- duplicate LSP Content-Length
- {error}
- LSP header exceeds size limit
- LSP initialize response is missing server capabilities
- payload too large
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/19bba02942511c1b.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/lsp/client.rs:609
return Ok(None);
};
if pos + 4 > MAX_LSP_HEADER_BYTES {
return Err(anyhow!("LSP header exceeds size limit"));
}
let header = std::str::from_utf8(&buf[..pos]).context("invalid LSP header encoding")?;
let mut content_length = None;
for line in header.split("\r\n") {
let (name, value) = line.split_once(':').context("malformed LSP header")?;
if name.eq_ignore_ascii_case("Content-Length") {
if content_length.is_some() {
return Err(anyhow!("duplicate LSP Content-Length"));
}
let length = value
.trim()
.parse::<usize>()
.context("invalid LSP Content-Length")?;
if length == 0 || length > MAX_LSP_FRAME_BYTES {
return Err(anyhow!("LSP frame exceeds size limit or is empty"));
}
content_length = Some(length);
}
}
Ok(Some((
pos + 4,
content_length.context("missing LSP Content-Length")?,
)))
}
/// Background task that consumes inbound JSON values, classifies them as
/// notifications/responses, and routes accordingly.
async fn dispatcher_task(
mut rx: mpsc::Receiver<Value>,
tx_diag: mpsc::Sender<DiagnosticMessage>,
pending: Arc<AsyncMutex<HashMap<i64, oneshot::Sender<Value>>>>,
) {
while let Some(value) = rx.recv().await {View on GitHub (pinned to 73e0f67d83)