Hmbown/CodeWhale · error · anyhow::Error

SSE buffer exceeded bytes — aborting stream

Error message

SSE buffer exceeded {MAX_SSE_BUF} bytes — aborting stream

What it means

A hard safety valve in the SSE parser: the accumulated unparsed byte buffer for the current SSE frame exceeded 10 MB (`MAX_SSE_BUF`), which can only happen if the stream is not producing newlines — i.e. malformed or malicious framing. The stream is aborted to prevent unbounded memory growth.

Solutions

  1. Check the response Content-Type is `text/event-stream` and the endpoint really speaks SSE
  2. Log the buffered bytes when this fires to identify what the server actually sent
  3. Fix the endpoint/proxy that is breaking SSE framing
  4. Verify TLS interception is not mangling the stream

Example fix

// before: endpoint returns JSON error page with 200
// after: check status/content-type and surface a clear upstream error before parsing
if !ct.starts_with("text/event-stream") { return Err(...); }
Defensive patterns

Strategy: validation

Validate before calling

// before parsing, verify the response is actually SSE
fn response_is_sse(ct: &str, status: u16) -> bool {
    status == 200 && ct.starts_with("text/event-stream")
}

Try / catch

match result {
    Err(e) if e.to_string().contains("SSE buffer exceeded") => {
        // framing broken — capture buffer sample, do NOT retry blindly
        dump_buffer_sample(); fail_with_upstream_context(e);
    }
    other => propagate(other),
}

Prevention

When it happens

Trigger: A server (or man-in-the-middle) streaming data without SSE line boundaries — non-SSE binary or HTML dumped into the connection, a broken Content-Type, or a runaway server bug never emitting `\n`.

Common situations: Pointing the client at an endpoint that returns an HTML error page or JSON body on a 200 without SSE framing; a proxy stripping or corrupting newlines; a compromised/misconfigured endpoint flooding data.

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


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/27d3f00ccc350dfc. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/client/chat.rs:1523

                            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 {
                    stream_failed = true;
                    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. Decode only after
                // a `\n` so an HTTP/2 DATA split mid-character cannot become
                // U+FFFD; genuine invalid bytes fail closed.
                let mut lines_processed = 0usize;
                loop {
                    let line = match take_sse_line(&mut byte_buf) {
                        Ok(Some(line)) => line,
                        Ok(None) => break,
                        Err(err) => {
                            decode_failed = true;
                            stream_failed = true;

View on GitHub (pinned to 73e0f67d83)