{"record":{"id":"27d3f00ccc350dfc","repo":"Hmbown/CodeWhale","slug":"sse-buffer-exceeded-max-sse-buf-bytes-aborting","errorCode":null,"errorMessage":"SSE buffer exceeded {MAX_SSE_BUF} bytes — aborting stream","messagePattern":"SSE buffer exceeded (.+?) bytes — aborting stream","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/client/chat.rs","lineNumber":1523,"sourceCode":"                            stream_start.elapsed().as_millis(),\n                            bytes_received,\n                            last_event_at.elapsed().as_millis(),\n                            response_headers,\n                        ));\n                        yield Err(anyhow::anyhow!(\"Stream read error: {e}\"));\n                        break;\n                    }\n                };\n\n                bytes_received = bytes_received.saturating_add(chunk.len());\n                last_event_at = std::time::Instant::now();\n                byte_buf.extend_from_slice(&chunk);\n\n                // Guard against unbounded buffer growth (e.g., malformed stream without newlines)\n                const MAX_SSE_BUF: usize = 10 * 1024 * 1024; // 10 MB\n                if byte_buf.len() > MAX_SSE_BUF {\n                    stream_failed = true;\n                    yield Err(anyhow::anyhow!(\"SSE buffer exceeded {MAX_SSE_BUF} bytes — aborting stream\"));\n                    break;\n                }\n\n                if byte_buf.len() > SSE_BACKPRESSURE_HIGH_WATERMARK {\n                    tokio::time::sleep(Duration::from_millis(SSE_BACKPRESSURE_SLEEP_MS)).await;\n                }\n\n                // Process complete SSE lines from the buffer. Decode only after\n                // a `\\n` so an HTTP/2 DATA split mid-character cannot become\n                // U+FFFD; genuine invalid bytes fail closed.\n                let mut lines_processed = 0usize;\n                loop {\n                    let line = match take_sse_line(&mut byte_buf) {\n                        Ok(Some(line)) => line,\n                        Ok(None) => break,\n                        Err(err) => {\n                            decode_failed = true;\n                            stream_failed = true;","sourceCodeStart":1505,"sourceCodeEnd":1541,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/client/chat.rs#L1505-L1541","documentation":"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.","triggerScenarios":"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`.","commonSituations":"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.","solutions":["Check the response Content-Type is `text/event-stream` and the endpoint really speaks SSE","Log the buffered bytes when this fires to identify what the server actually sent","Fix the endpoint/proxy that is breaking SSE framing","Verify TLS interception is not mangling the stream"],"exampleFix":"// before: endpoint returns JSON error page with 200\n// after: check status/content-type and surface a clear upstream error before parsing\nif !ct.starts_with(\"text/event-stream\") { return Err(...); }","handlingStrategy":"validation","validationCode":"// before parsing, verify the response is actually SSE\nfn response_is_sse(ct: &str, status: u16) -> bool {\n    status == 200 && ct.starts_with(\"text/event-stream\")\n}","typeGuard":null,"tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"SSE buffer exceeded\") => {\n        // framing broken — capture buffer sample, do NOT retry blindly\n        dump_buffer_sample(); fail_with_upstream_context(e);\n    }\n    other => propagate(other),\n}","preventionTips":["Check Content-Type is text/event-stream before entering the parse loop","Reject non-SSE 200 bodies (HTML/JSON error pages) early","Investigate TLS-intercepting proxies that mangle framing","Keep the buffer guard in place — it protects against runaway servers"],"tags":["sse","streaming","memory","protocol"],"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-23T08:17:48.524Z"}