Hmbown/CodeWhale · error
{err}
Error message
{err} What it means
The Anthropic SSE reader decodes only complete lines and decodes them strictly: a line containing bytes that are not valid UTF-8 produces this error instead of silently substituting U+FFFD replacement characters (a deliberate contract, tracked as #5374). `take_sse_line` splits on `\n`, strips a trailing `\r`, then runs `std::str::from_utf8`; on failure the `InvalidSseUtf8` error (with `valid_up_to`/`error_len`) is surfaced and the stream terminates.
Source
Thrown at crates/tui/src/client/anthropic.rs:344
stream_idle_timeout,
bytes_received,
stream_start.elapsed(),
last_chunk_at.elapsed(),
)));
return;
}
};
bytes_received += chunk.len();
last_chunk_at = std::time::Instant::now();
buffer.extend_from_slice(&chunk);
loop {
let line = match super::take_sse_line(&mut buffer) {
Ok(Some(line)) => line,
Ok(None) => break,
Err(err) => {
yield Err(anyhow::anyhow!("{err}"));
return;
}
};
// `event:` lines are redundant (the data payload carries
// `type`) and comment/heartbeat lines are ignorable.
let Some(data) = super::extract_sse_data_value(&line) else {
continue;
};
match convert_anthropic_sse_data(data) {
Some(Ok(StreamEvent::Error { error })) => {
let (error_type, message) = anthropic_error_fields(&error);
yield Err(anyhow::anyhow!(
"Anthropic stream error ({error_type}): {message}"
));
return;
}View on GitHub (pinned to 8880682c63)
Solutions
- Bypass the intermediary: connect directly to the API endpoint without the SSL-inspecting proxy/VPN and retry.
- Fix proxy configuration: disable response buffering/transcoding for `text/event-stream` and ensure compression is applied once.
- If you control the server, audit what is written into the stream — the error means raw invalid bytes on a complete line.
- Report persistent occurrences to the provider with a timestamp; strict rejection here is intentional so corruption is visible rather than silently mangled.
Defensive patterns
Strategy: try-catch
Type guard
fn is_invalid_sse_utf8_error(e: &anyhow::Error) -> bool {
e.to_string().contains("invalid UTF-8") || e.to_string().contains("valid up to")
} Try / catch
// The stream terminates on invalid UTF-8 by design; surface the cause,
// do not swallow it into replacement characters.
match stream.next().await {
Some(Err(e)) if is_invalid_sse_utf8_error(&e) => {
log::error!("SSE stream corrupted (invalid UTF-8) — bypass SSL-inspecting proxies");
return Err(e); // keep corruption visible instead of mangling output
}
other => handle(other),
} Prevention
- Exclude API domains from SSL-inspection/antivirus appliances that rewrite event-stream bodies.
- Ensure reverse proxies apply content-encoding exactly once and disable SSE buffering/transcoding.
- Treat this error as an infrastructure signal, not a data loss — strict rejection exists so corruption is never silently masked.
When it happens
Trigger: A gateway/MITM proxy re-encoding or corrupting the event stream (e.g. broken chunked-compression, charset transcoding); a provider bug emitting binary garbage inside a `data:` line; a misbehaving cache layer serving mixed-encoding fragments. Because line splitting happens on `\n` bytes, normal multi-byte text split across reads is NOT a cause — only genuinely invalid byte sequences trigger it.
Common situations: Antivirus/SSL-inspection appliances rewriting SSE bodies; reverse proxies mis-applying gzip twice; self-hosted anthropic-compatible servers writing log bytes into the stream; extremely rare provider-side serialization bugs.
Related errors
- {err}
- Stream read error: {e}
- SSE stream idle timeout after {}s — no data received (bytes_
- Anthropic stream error ({error_type}): {message}
- invalid SSE JSON: {e}
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/17d420e74c3fbd44.
Report an issue: GitHub.