openai/codex · error · TransportError

connection failed

Error message

connection failed: {0}

What it means

TransportError::Connection wraps a reqwest error for which is_connect() is true; the reqwest error is preserved as #[source] and the request URL is stripped via without_url() (transport.rs:82). It means the transport never completed an HTTP exchange: DNS resolution, TCP connect, or the TLS handshake to the origin or proxy failed. Inspect .source() for the underlying reqwest error details.

Solutions

  1. Inspect the preserved source error (error.source() downcast to reqwest::Error) to distinguish DNS vs refused vs TLS failure
  2. Verify host, port, and reachability of the endpoint directly (dig/curl) and through the proxy if one is required
  3. For TLS causes, install the enterprise root CA via the custom-CA transport path (build_reqwest_client_with_custom_ca) instead of disabling verification
  4. Retry with backoff: connection failures are often transient (restarts, port exhaustion)

Example fix

// before
match transport.execute(req).await {
    Err(e) => log::error!("request failed: {e}"), // opaque
    r => r?,
}

// after: classify using the preserved reqwest source
if let TransportError::Connection(source) = &error {
    if source.is_connect() && source.to_string().contains("dns error") { /* host/port config */ }
}
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight DNS check before first use (cheap, caches at the resolver)
async fn endpoint_reachable(host: &str, port: u16) -> bool {
    tokio::net::lookup_host((host, port)).await.is_ok()
}

Type guard

fn is_connection_failure(e: &TransportError) -> bool {
    matches!(e, TransportError::Connection(_))
}

Try / catch

if let TransportError::Connection(source) = &error {
    let detail = source.to_string();
    if detail.contains("dns error") { return ConfigError::BadHost(detail); }
    if detail.contains("tls") || detail.contains("certificate") { return ConfigError::Tls(detail); }
}
// otherwise: transient connect failure, retry idempotent requests with backoff

Prevention

When it happens

Trigger: HttpTransport::execute/stream fails during send with a reqwest is_connect() error: DNS lookup failure (unknown host), connection refused (server down or wrong port), TLS handshake or certificate failure while connecting, or an unreachable configured proxy.

Common situations: Wrong hostname or port in configuration, DNS/hosts-file breakage, firewall blocking egress, corporate proxy required but not configured, self-signed or enterprise CA not installed via the custom-CA path, server temporarily down for deployment.

Understand the failure class

Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.

Related errors


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

Appendix: source

Thrown at codex-rs/http-client/src/error.s:21

//! 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),
}

View on GitHub (pinned to 339751715c)