{"record":{"id":"cfd45867e54a0a24","repo":"openai/codex","slug":"stream-failed-0","errorCode":null,"errorMessage":"stream failed: {0}","messagePattern":"stream failed: (.+?)","errorType":"exception","errorClass":"StreamError","httpStatus":null,"severity":"error","filePath":"codex-rs/http-client/src/error.rs","lineNumber":31,"sourceCode":"        url: Option<String>,\n        headers: Option<HeaderMap>,\n        body: Option<String>,\n    },\n    #[error(\"retry limit reached\")]\n    RetryLimit,\n    #[error(\"timeout\")]\n    Timeout,\n    #[error(\"connection failed: {0}\")]\n    Connection(#[source] HttpError),\n    #[error(\"network error: {0}\")]\n    Network(String),\n    #[error(\"request build error: {0}\")]\n    Build(String),\n}\n\n#[derive(Debug, Error)]\npub enum StreamError {\n    #[error(\"stream failed: {0}\")]\n    Stream(String),\n    #[error(\"timeout\")]\n    Timeout,\n}\n","sourceCodeStart":13,"sourceCodeEnd":36,"githubUrl":"https://github.com/openai/codex/blob/339751715c64496cb86246bfb3935f40e309dd3d/codex-rs/http-client/src/error.rs#L13-L36","documentation":"StreamError::Stream(String) is defined in the shared HTTP transport's error module for consumers of response byte/SSE streams (exported at lib.rs:32). It reports that consuming the stream failed after a successful start, carrying the underlying failure's message as a plain string — typically a connection reset or protocol/decode failure mid-body, as opposed to StreamError::Timeout which means no data arrived within the deadline.","triggerScenarios":"Polling a response stream where the underlying read fails after headers were received: the peer or a proxy resets the connection mid-body, chunked transfer framing is malformed, or a body decoder errors while yielding bytes.","commonSituations":"Long-lived SSE/model-token streams dropped by middlebox idle timeouts, proxies with response-size or buffering limits that terminate long responses, unstable mobile or VPN links interrupting downloads.","solutions":["Inspect the embedded message string to identify the failing layer (TCP reset, decode failure, protocol error)","Re-establish the stream; for SSE-style endpoints resume from the last processed event id or offset if the protocol supports it","Raise or disable idle/response timeouts on intermediaries (proxy, ALB, CDN) in the stream path","Bypass the proxy for the streaming host to isolate which hop terminates the response"],"exampleFix":"// before\nwhile let Some(chunk) = stream.next().await { out.extend(&chunk?); } // StreamError::Stream aborts the consumer\n\n// after: supervised consume with resume\nloop {\n    match consume_from(&mut stream, &mut checkpoint).await {\n        Err(StreamError::Stream(msg)) => { log::warn!(\"stream reset: {msg}\"); stream = reconnect(checkpoint).await?; }\n        other => break other?,\n    }\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":"fn is_stream_failure(e: &StreamError) -> bool {\n    matches!(e, StreamError::Stream(_))\n}","tryCatchPattern":"match stream.next().await {\n    Some(Err(StreamError::Stream(msg))) => {\n        tracing::warn!(%msg, \"stream interrupted, reconnecting\");\n        stream = resume_from(checkpoint).await?;\n    }\n    Some(Err(StreamError::Timeout)) => { /* extend deadline, poll again */ }\n    other => return other.transpose(),\n}","preventionTips":["Checkpoint consumed offsets so an interrupted stream can resume instead of restarting","Add application-level heartbeats or subscribe to server keep-alives to distinguish idle from dead","Bound retry storms with jitter and a maximum reconnect count","Raise idle timeouts on proxies and load balancers in the streaming path"],"tags":["network","streaming","sse","rust"],"backgroundTag":"response-stream-interrupted","analyzedSha":"339751715c64496cb86246bfb3935f40e309dd3d","analyzedAt":"2026-08-25T05:35:09.876Z","schemaVersion":2},"datasetVersion":"2026-08-25T06:17:31.827Z"}