{"record":{"id":"2ec0448430871da0","repo":"Hmbown/CodeWhale","slug":"stream-read-error-e-2ec044","errorCode":null,"errorMessage":"Stream read error: {e}","messagePattern":"Stream read error: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/client/responses.rs","lineNumber":239,"sourceCode":"            let mut saw_tool_call = false;\n            let mut usage_data: Option<Usage> = None;\n            // Raw byte buffer: decode only COMPLETE lines so a multi-byte\n            // UTF-8 char split across two network reads is never corrupted\n            // to U+FFFD (line boundaries are ASCII). Mirrors chat.rs.\n            let mut buffer: Vec<u8> = Vec::new();\n            let mut done = false;\n            let mut content_block_counter: u32 = 0;\n            let stream_start = std::time::Instant::now();\n            let mut last_chunk_at = std::time::Instant::now();\n            let mut bytes_received: usize = 0;\n\n            tokio::pin!(byte_stream);\n\n            while !done {\n                let chunk = match tokio::time::timeout(stream_idle_timeout, byte_stream.next()).await {\n                    Ok(Some(Ok(chunk))) => chunk,\n                    Ok(Some(Err(e))) => {\n                        yield Err(anyhow::anyhow!(\"Stream read error: {e}\"));\n                        return;\n                    }\n                    Ok(None) => break,\n                    Err(_) => {\n                        yield Err(anyhow::anyhow!(super::stream_entry::idle_timeout_message(\n                            stream_idle_timeout,\n                            bytes_received,\n                            stream_start.elapsed(),\n                            last_chunk_at.elapsed(),\n                        )));\n                        return;\n                    }\n                };\n\n                bytes_received += chunk.len();\n                last_chunk_at = std::time::Instant::now();\n                buffer.extend_from_slice(&chunk);\n","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/tui/src/client/responses.rs#L221-L257","documentation":"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`.","triggerScenarios":"Connection reset or HTTP/2 RST_STREAM during the Responses API stream; decompression failure; proxy cutting the long-lived connection.","commonSituations":"Long streaming completions through proxies; unstable networks; server-side connection recycling.","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"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":"fn is_stream_read_error(err: &anyhow::Error) -> bool {\n    err.to_string().starts_with(\"Stream read error\")\n}","tryCatchPattern":"match stream.next().await {\n    Some(Err(e)) if is_stream_read_error(&e) => {\n        backoff().await;\n        stream = client.reopen_responses_stream(request).await?;\n    }\n    Some(Err(e)) => return Err(e),\n    other => { /* forward */ }\n}","preventionTips":["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"],"tags":["openai","responses-api","network","streaming","reqwest"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}