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

  1. Raise the per-request deadline (Request.timeout) to match the endpoint's worst-case response time
  2. 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
  3. Verify the endpoint actually responds within the budget (curl the same URL) and check for proxy-added latency
  4. 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

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

Related errors


AI-assisted analysis of openai/codex@339751715c (2026-08-25). Data as JSON: /api/errors/97b9c07d7c9a861c. Report an issue: GitHub.