openai/codex · error · TransportError
timeout
Error message
timeout
What it means
TransportError::Timeout is returned by the shared Codex HTTP transport (ReqwestTransport::execute / stream) when the underlying reqwest error reports is_timeout(). It is produced by map_error in codex-rs/http-client/src/transport.rs:80-88 and covers the initial send, the buffered body read (resp.bytes()), and every item of the byte stream. The variant carries no context (no URL, no elapsed time), so correlate it with your own request logging.
Source
Thrown at codex-rs/http-client/src/error.rs:19
//! Errors returned by the shared Codex HTTP transport.
use crate::client::HttpError;
use http::HeaderMap;
use http::StatusCode;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum TransportError {
#[error("http {status}: {body:?}")]
Http {
status: StatusCode,
url: Option<String>,
headers: Option<HeaderMap>,
body: Option<String>,
},
#[error("retry limit reached")]
RetryLimit,
#[error("timeout")]
Timeout,
#[error("connection failed: {0}")]
Connection(#[source] HttpError),
#[error("network error: {0}")]
Network(String),
#[error("request build error: {0}")]
Build(String),
}
#[derive(Debug, Error)]
pub enum StreamError {
#[error("stream failed: {0}")]
Stream(String),
#[error("timeout")]
Timeout,
}
View on GitHub (pinned to 339751715c)
Solutions
- Raise the per-request deadline (Request.timeout) to match the endpoint's worst-case response time
- For streaming endpoints use HttpTransport::stream instead of buffered execute, and bound only connection setup via HttpClientBuilder::connect_timeout instead of a whole-request timeout
- Verify the endpoint actually responds within the budget (curl the same URL) and check for proxy-added latency
- Retry with capped backoff and jitter: timeouts are frequently transient
Example fix
// before
let request = Request {
timeout: Some(Duration::from_secs(5)),
..req
};
transport.execute(request).await?; // TransportError::Timeout on slow endpoints
// after: size the deadline to the endpoint, or bound only the connect phase
let request = Request {
timeout: Some(Duration::from_secs(120)),
..req
};
// connect-only bound: build the client with HttpClientBuilder::connect_timeout(...) Defensive patterns
Strategy: retry
Type guard
fn is_transport_timeout(e: &TransportError) -> bool {
matches!(e, TransportError::Timeout)
} Try / catch
match transport.execute(req).await {
Err(TransportError::Timeout) => retry_with_jitter(req, MAX_ATTEMPTS).await,
Err(TransportError::Connection(source)) => /* classify via source, maybe retry */,
Err(TransportError::Http { status, .. }) if status.is_server_error() => /* retry */,
other => other,
} Prevention
- Size per-request timeouts from measured endpoint p99 latency, not defaults
- Use connect-only bounds (HttpClientBuilder::connect_timeout) for streaming paths so slow bodies are not cut off
- Add a deadline budget that subtracts elapsed time before each retry
- Alert on timeout rate per destination to catch slow degradation early
When it happens
Trigger: Calling HttpTransport::execute or HttpTransport::stream on a Request whose timeout field is Some(Duration) (applied at transport.rs:69-71), or a client built with a connect timeout, where reqwest reports is_timeout(): the per-request deadline elapsed during connect, send, or response-body read.
Common situations: Aggressive per-request timeouts against slow streaming/LLM endpoints, connect timeouts through corporate proxies, servers that accept the connection but stall before responding, high-latency CI or mobile networks.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- route-aware request timed out
- Luna Responses WebSocket connection timed out
- network error: {0}
- too many redirects
- standalone Codex updater request failed with status {status}
AI-assisted analysis of openai/codex@339751715c (2026-08-25).
Data as JSON: /api/errors/97b9c07d7c9a861c.
Report an issue: GitHub.