Hmbown/CodeWhale · error
SSE buffer exceeded {MAX_SSE_BUF} bytes — aborting stream
Error message
SSE buffer exceeded {MAX_SSE_BUF} bytes — aborting stream What it means
Guard against unbounded buffer growth: the raw SSE byte buffer grew past 10 MB without yielding a complete line, so the client aborts the stream. A legitimate SSE response virtually never has 10 MB with no newline; this indicates a malformed stream — data arriving with no line delimiters at all.
Source
Thrown at crates/tui/src/client/chat.rs:1344
(elapsed: {}ms, bytes_received: {}, ms_since_last_event: {}, headers: {})",
stream_start.elapsed().as_millis(),
bytes_received,
last_event_at.elapsed().as_millis(),
response_headers,
));
yield Err(anyhow::anyhow!("Stream read error: {e}"));
break;
}
};
bytes_received = bytes_received.saturating_add(chunk.len());
last_event_at = std::time::Instant::now();
byte_buf.extend_from_slice(&chunk);
// Guard against unbounded buffer growth (e.g., malformed stream without newlines)
const MAX_SSE_BUF: usize = 10 * 1024 * 1024; // 10 MB
if byte_buf.len() > MAX_SSE_BUF {
yield Err(anyhow::anyhow!("SSE buffer exceeded {MAX_SSE_BUF} bytes — aborting stream"));
break;
}
if byte_buf.len() > SSE_BACKPRESSURE_HIGH_WATERMARK {
tokio::time::sleep(Duration::from_millis(SSE_BACKPRESSURE_SLEEP_MS)).await;
}
// Process complete SSE lines from the buffer. Strict UTF-8:
// never `from_utf8_lossy` here — a mid-character TCP split
// stays in `byte_buf` until `\n`, and a genuinely invalid
// line fails closed instead of injecting U+FFFD (#5374).
let mut lines_processed = 0usize;
loop {
let line = match super::take_sse_line(&mut byte_buf) {
Ok(Some(line)) => line,
Ok(None) => break,
Err(err) => {
yield Err(anyhow::anyhow!("{err}"));View on GitHub (pinned to 8880682c63)
Solutions
- Verify the endpoint actually returns an SSE stream (correct URL and `stream: true` request shape)
- Retry once — an occasional malformed response is transient
- Capture the buffered bytes to identify what is actually being sent
- If deterministic, the endpoint/URL is wrong or the upstream is broken — report or fix the route
Defensive patterns
Strategy: try-catch
Type guard
fn is_sse_buffer_overflow(err: &anyhow::Error) -> bool {
err.to_string().starts_with("SSE buffer exceeded")
} Try / catch
match stream.next().await {
Some(Err(e)) if is_sse_buffer_overflow(&e) => {
// 10MB with no newline = not an SSE stream; do not retry the same URL blindly
return Err(e.context("endpoint is not returning newline-delimited SSE"));
}
other => { /* forward */ }
} Prevention
- Verify the endpoint and request shape actually produce SSE before streaming
- Do not disable or raise the buffer guard — it exists to stop malformed streams
- Test new base URLs with a tiny request first to confirm line-delimited output
When it happens
Trigger: Server sends one giant unbroken line (no `\n`); a misbehaving proxy strips newlines; a non-SSE body (binary, JSON blob, HTML error page) is served on the streaming endpoint.
Common situations: Wrong base URL where the endpoint returns a plain JSON body instead of SSE; upstream bug emitting an unterminated payload; intermediary response rewriting.
Related errors
- Runtime API request failed (${status}): ${message}
- Runtime API request failed (${status}): ${message}
- Runtime API request failed (${status}): ${message}
- Stream read error: {e}
- SSE stream idle timeout after {}s — no data received (bytes_
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/27d3f00ccc350dfc.
Report an issue: GitHub.