openai/codex · error · RouteAwareClientPoolError

failed to resolve the outbound proxy route: {0}

Error message

failed to resolve the outbound proxy route: {0}

What it means

RouteAwareClientPoolError::Resolve is produced in client_for_url_with_resolver (route_aware_client_pool.rs:723-725) when the async route resolver returns an io::Error. The resolver is HttpClientFactory::resolve_proxy_route_async (outbound_proxy.rs:242-276): on Windows/macOS the platform lookup runs under spawn_blocking, so the io::Error typically comes from the semaphore acquire or the blocking task failing to join (runtime shutdown, task panic); the synchronous resolution itself falls back to env/direct instead of erroring. failure_class() maps it to ProxyResolutionUnavailable (or TlsError when the io::Error carries a rustls error).

Source

Thrown at codex-rs/http-client/src/route_aware_client_pool.rs:81

    custom_ca_fallback: CustomCaFallback,
    clients: Arc<Mutex<HashMap<OutboundProxyRoute, HttpClient>>>,
    rustls_clients: Option<RustlsClientCache>,
}

impl fmt::Debug for RouteAwareClientPool {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        formatter
            .debug_struct("RouteAwareClientPool")
            .field("http_client_factory", &self.http_client_factory)
            .field("route_class", &self.route_class)
            .finish_non_exhaustive()
    }
}

/// Error returned when selecting a route or constructing its pooled HTTP client.
#[derive(Debug, thiserror::Error)]
pub enum RouteAwareClientPoolError {
    #[error("failed to resolve the outbound proxy route: {0}")]
    Resolve(#[source] io::Error),
    #[error(transparent)]
    Build(#[from] BuildRouteAwareHttpClientError),
}

/// Error returned while building, routing, or sending a route-aware request.
#[derive(Debug, thiserror::Error)]
pub enum RouteAwareRequestError {
    #[error(transparent)]
    Request(#[from] reqwest::Error),
    #[error(transparent)]
    Route(#[from] RouteAwareClientPoolError),
    #[error("failed to build route-aware request: {0}")]
    Build(String),
    #[error("redirect target uses unsupported URL scheme: {0}")]
    UnsupportedRedirectScheme(String),
    #[error("too many redirects")]
    TooManyRedirects,

View on GitHub (pinned to 339751715c)

Solutions

  1. Check whether the runtime is being shut down or the send future was cancelled while platform proxy resolution was in flight; drain in-flight requests before shutdown
  2. Retry the send: successful resolutions are cached (60s TTL) so a retry usually hits the cache or completes the lookup
  3. Update codex-rs if the platform binding panic is a known issue, and capture the io::Error's source for the report
  4. As a workaround, run with OutboundProxyPolicy::ReqwestDefault or env-only proxies to skip platform resolution entirely

Example fix

// before
let resp = pool.get(url).send().await?; // Resolve(io::Error) aborts the caller

// after: retry once, then fall back to a direct-route factory
let resp = match pool.get(url.clone()).send().await {
    Err(RouteAwareRequestError::Route(RouteAwareClientPoolError::Resolve(_))) =>
        pool.get(url).send().await?,
    other => other?,
};
Defensive patterns

Strategy: fallback

Type guard

fn is_route_resolve_error(e: &RouteAwareRequestError) -> bool {
    matches!(e, RouteAwareRequestError::Route(RouteAwareClientPoolError::Resolve(_)))
}

Try / catch

match error {
    RouteAwareRequestError::Route(RouteAwareClientPoolError::Resolve(io)) => {
        tracing::warn!(source = %io, "proxy route resolution unavailable");
        // resolution results are cached; one retry is cheap, then degrade
        retry_once_or_direct(factory).await
    }
    _ => return Err(error),
}

Prevention

When it happens

Trigger: Sending via RouteAwareClientPool with RespectSystemProxy on Windows/macOS while the spawn_blocking PAC/WinHTTP/system-proxy lookup fails to join: the tokio runtime is shutting down, the request future is cancelled mid-lookup, or the platform binding panics. It propagates to callers as RouteAwareRequestError::Route(RouteAwareClientPoolError::Resolve(..)).

Common situations: Dropping request futures during graceful-shutdown drains in servers, test harnesses tearing down the runtime while sends are in flight, bugs in platform proxy bindings after an upgrade.

Related errors


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