Hmbown/CodeWhale · error
Stream read error: {e}
Error message
Stream read error: {e} What it means
While reading the Responses API SSE body, reqwest returned an error mid-stream (the `Ok(Some(Err(e)))` arm). The client yields this error and returns, ending the stream; the adjacent timeout arm handles idle expiry with the shared `idle_timeout_message`.
Source
Thrown at crates/tui/src/client/responses.rs:239
let mut saw_tool_call = false;
let mut usage_data: Option<Usage> = None;
// Raw byte buffer: decode only COMPLETE lines so a multi-byte
// UTF-8 char split across two network reads is never corrupted
// to U+FFFD (line boundaries are ASCII). Mirrors chat.rs.
let mut buffer: Vec<u8> = Vec::new();
let mut done = false;
let mut content_block_counter: u32 = 0;
let stream_start = std::time::Instant::now();
let mut last_chunk_at = std::time::Instant::now();
let mut bytes_received: usize = 0;
tokio::pin!(byte_stream);
while !done {
let chunk = match tokio::time::timeout(stream_idle_timeout, byte_stream.next()).await {
Ok(Some(Ok(chunk))) => chunk,
Ok(Some(Err(e))) => {
yield Err(anyhow::anyhow!("Stream read error: {e}"));
return;
}
Ok(None) => break,
Err(_) => {
yield Err(anyhow::anyhow!(super::stream_entry::idle_timeout_message(
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);
View on GitHub (pinned to 8880682c63)
Solutions
- Retry with backoff — most mid-body transport errors are transient
- If it recurs at a consistent point, check for intermediary time/size limits and bypass them
- On persistent failure, test the same request non-streaming to isolate the transport from the request
Defensive patterns
Strategy: retry
Type guard
fn is_stream_read_error(err: &anyhow::Error) -> bool {
err.to_string().starts_with("Stream read error")
} Try / catch
match stream.next().await {
Some(Err(e)) if is_stream_read_error(&e) => {
backoff().await;
stream = client.reopen_responses_stream(request).await?;
}
Some(Err(e)) => return Err(e),
other => { /* forward */ }
} Prevention
- Retry mid-stream transport failures with backoff before escalating
- Compare streaming vs non-streaming behavior to isolate transport-only issues
- Watch for consistent failure points that indicate intermediary limits
When it happens
Trigger: Connection reset or HTTP/2 RST_STREAM during the Responses API stream; decompression failure; proxy cutting the long-lived connection.
Common situations: Long streaming completions through proxies; unstable networks; server-side connection recycling.
Related errors
- Stream read error: {e}
- SSE stream idle timeout after {}s — no data received (bytes_
- provider stream error: {error}
- Stream read error: {e}
- SSE stream idle timeout after {}s — no data received (bytes_
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/2ec0448430871da0.
Report an issue: GitHub.