Hmbown/CodeWhale · error
MCP SSE frame exceeded
Error message
MCP SSE frame exceeded {} bytes without a separator — aborting What it means
SSE frames are buffered until a separator (blank line delimiting an event) is found. If the buffer grows past `MAX_SSE_FRAME_BYTES` without any separator, the stream is presumed malicious or broken and aborted rather than consuming unbounded memory.
Solutions
- Confirm the URL returns actual `text/event-stream` SSE data with proper blank-line separators
- Check for proxies/CDNs buffering or mangling the stream; connect directly or fix the proxy
- If a single legitimate event is truly huge, raise `MAX_SSE_FRAME_BYTES` (server-side fix preferred)
- Reduce the event payload size on the server
Example fix
// before
// client pointed at a plain JSON endpoint
{"url": "https://host/api/events.json"}
// after
{"url": "https://host/sse"} // real text/event-stream endpoint Defensive patterns
Strategy: try-catch
Validate before calling
// verify endpoint speaks SSE
let ct = reqwest::get(url).await?.headers().get("content-type")
.and_then(|v| v.to_str().ok()).unwrap_or("");
if !ct.starts_with("text/event-stream") {
return Err(anyhow!("not an SSE endpoint"));
} Try / catch
match run_sse_loop(...).await {
Err(e) if e.to_string().contains("without a separator") => {
error!("endpoint is not emitting valid SSE framing; check URL/proxy");
}
other => other?,
} Prevention
- Point only at real text/event-stream endpoints
- Avoid proxies that buffer or rewrite streaming responses
- Keep individual SSE events under the client frame cap
When it happens
Trigger: A server (or middlebox) sends a continuous byte stream with no SSE event separator, or a single event larger than the frame cap; corrupted/garbage responses not actually speaking SSE.
Common situations: Pointing the client at a plain HTTP streaming endpoint (non-SSE) or a binary stream; a buggy proxy mangling framing; an enormous single event from a misbehaving server.
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
- MCP SSE server sent a message before declaring its endpoint
- SSE buffer exceeded bytes — aborting stream
- SSE endpoint not received within
- {err}
- JSON-RPC line exceeded the
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/e575ee14bdf19ee5.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/mcp/sse.rs:158
tracing::debug!("SSE loop cancelled");
break;
}
let item = tokio::select! {
_ = cancel_token.cancelled() => {
tracing::debug!("SSE loop shutting down");
break;
}
item = stream.next() => {
match item {
Some(i) => i,
None => break,
}
}
};
let chunk = item?;
buffer.extend_from_slice(&chunk);
if buffer.len() > MAX_SSE_FRAME_BYTES {
anyhow::bail!(
"MCP SSE frame exceeded {} bytes without a separator — aborting",
MAX_SSE_FRAME_BYTES
);
}
while let Some((pos, separator_len)) = find_sse_event_separator_bytes(&buffer) {
// Complete block: decoding cannot split a multi-byte char.
let event_block = String::from_utf8_lossy(&buffer[..pos]).into_owned();
buffer.drain(..pos + separator_len);
let mut event_type = "message";
let mut data = String::new();
for line in event_block.lines() {
if let Some(value) = sse_field_value(line, "event:") {
event_type = value;
} else if let Some(value) = sse_field_value(line, "data:") {
if !data.is_empty() {View on GitHub (pinned to 73e0f67d83)