Hmbown/CodeWhale · error · anyhow::Error
runtime SSE frame exceeded
Error message
runtime SSE frame exceeded {MAX_SSE_FRAME_BYTES} bytes without a frame delimiter What it means
The app-server client reads a runtime SSE (Server-Sent Events) stream and accumulates chunks in a buffer. If the buffer grows past MAX_SSE_FRAME_BYTES without a complete frame delimiter appearing, this error is thrown to bound memory use, since a valid SSE frame can never legitimately be that large.
Solutions
- Inspect what the runtime is actually streaming (curl the SSE endpoint) to find the oversized frame's origin.
- Check for proxies/load balancers between client and runtime that strip SSE newlines or re-chunk the body.
- Verify the runtime version matches what the client expects; upgrade or downgrade so framing is standard SSE.
- If a legitimate event is too large, reduce the event payload size on the runtime side instead of raising the limit.
Defensive patterns
Strategy: validation
Try / catch
// Rust
match client.poll_events(...) {
Err(e) if e.to_string().contains("SSE frame exceeded") => {
log::error!("runtime streamed an oversized frame; check proxies/runtime version");
// fail the turn rather than retrying blindly
}
other => other,
} Prevention
- Do not place newline-stripping proxies between client and runtime.
- Keep runtime and client versions aligned so SSE framing is standard.
- Keep individual event payloads small on the runtime side.
When it happens
Trigger: Any call that consumes the runtime's SSE event stream (polling run events via HTTP chunked response) where a single event frame exceeds the configured byte limit before a newline/frame delimiter arrives.
Common situations: A malicious or broken runtime/server streaming a huge un-delimited body; a proxy mangling SSE framing so newlines are lost; a misconfigured runtime emitting extremely large payloads as one event.
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
- {err}
- PythonRuntime::with_state_path is deprecated — use…
- runtime event stream ended before turn.completed
- Runtime event stream ended inside a frame
- SSE buffer exceeded bytes — aborting stream
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/2e30c097cbdf64e7.
Report an issue: GitHub.
Appendix: source
Thrown at crates/app-server/src/lib.rs:1923
since_seq: u64,
mut transcript: Option<&mut TurnTranscript>,
) -> Result<(u64, TurnTerminalStatus, Option<String>)> {
let mut response = self
.authed(self.client.get(format!(
"{}/v1/threads/{thread_id}/events?since_seq={since_seq}",
self.base_url
)))
.send()
.await?
.error_for_status()?;
let mut buffer = Vec::new();
let mut last_seq = since_seq;
while let Some(chunk) = response.chunk().await? {
buffer.extend_from_slice(&chunk);
if buffer.len() > MAX_SSE_FRAME_BYTES {
bail!(
"runtime SSE frame exceeded {MAX_SSE_FRAME_BYTES} bytes without a frame delimiter"
);
}
while let Some(frame_bytes) = take_sse_frame(&mut buffer) {
let Some((event_name, frame_data)) = parse_sse_frame(&frame_bytes) else {
continue;
};
let envelope: Value = serde_json::from_str(&frame_data)
.with_context(|| format!("invalid SSE json for {event_name}: {frame_data}"))?;
if let Some(seq) = envelope.get("seq").and_then(Value::as_u64) {
last_seq = last_seq.max(seq);
}
if envelope.get("turn_id").and_then(Value::as_str) != Some(turn_id) {
continue;
}
let payload = envelope.get("payload").cloned().unwrap_or(Value::Null);
match event_name.as_str() {
"item.delta" => {View on GitHub (pinned to 73e0f67d83)