{"record":{"id":"b262ba88f626a9c3","repo":"openai/codex","slug":"network-error-0","errorCode":null,"errorMessage":"network error: {0}","messagePattern":"network error: (.+?)","errorType":"exception","errorClass":"TransportError","httpStatus":null,"severity":"error","filePath":"codex-rs/http-client/src/error.rs","lineNumber":23,"sourceCode":"use http::StatusCode;\nuse thiserror::Error;\n\n#[derive(Debug, Error)]\npub enum TransportError {\n    #[error(\"http {status}: {body:?}\")]\n    Http {\n        status: StatusCode,\n        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":5,"sourceCodeEnd":36,"githubUrl":"https://github.com/openai/codex/blob/339751715c64496cb86246bfb3935f40e309dd3d/codex-rs/http-client/src/error.rs#L5-L36","documentation":"TransportError::Network is the catch-all branch of ReqwestTransport::map_error (transport.rs:86): any reqwest failure that is neither is_connect() nor is_timeout() is stringified into this variant. Typical contents are mid-body failures (connection reset after headers, invalid chunked transfer encoding, truncated body) and reqwest request/body errors. Unlike Connection, the original reqwest error is not kept as a source, only its Display string.","triggerScenarios":"builder.send() or resp.bytes() fails with a reqwest error that is neither connect nor timeout: connection reset while reading the response body, broken chunked framing, Content-Length mismatch where the peer closes early, or request errors raised inside reqwest during send.","commonSituations":"Proxies or load balancers killing keep-alive connections mid-response, servers closing connections before the body completes, VPN or NAT idle reaping, response buffering middleboxes that truncate large payloads.","solutions":["Read the embedded message string: it is reqwest::Error's Display and names the failing phase (body decode, request, etc.)","Enable the transport's debug logging (ReqwestTransport logs 'Request failed' with URL and status) to capture context the variant itself drops","Retry idempotent requests with backoff: mid-body resets are frequently keep-alive races that succeed on a fresh connection","If it recurs on one endpoint only, capture the exchange through a debugging proxy to see where the body is truncated"],"exampleFix":"// before\nlet resp = transport.execute(req).await?;\n\n// after: treat Network as transient for idempotent requests\nlet resp = retry_with_backoff(3, || transport.execute(req.clone())).await?;","handlingStrategy":"retry","validationCode":null,"typeGuard":"fn is_network_error(e: &TransportError) -> bool {\n    matches!(e, TransportError::Network(_))\n}","tryCatchPattern":"match transport.execute(req).await {\n    Err(e @ TransportError::Network(msg)) => {\n        tracing::warn!(error = %msg, \"network failure\");\n        retry_if_idempotent(req, &e).await\n    }\n    other => other,\n}","preventionTips":["Distinguish Network from Connection and Timeout first: it is the residual class and needs the message string to diagnose","Retry only idempotent methods; mid-body failures can duplicate side effects otherwise","Log the embedded reqwest Display string alongside your own request id to keep diagnosis possible","Reuse connections aggressively but bound pool idle lifetime to avoid stale keep-alive resets"],"tags":["network","http","reqwest","rust"],"backgroundTag":"http-request-send-failed","analyzedSha":"339751715c64496cb86246bfb3935f40e309dd3d","analyzedAt":"2026-08-25T05:35:09.876Z","schemaVersion":2},"datasetVersion":"2026-08-25T06:17:31.827Z"}