openai/codex · error · RouteAwareRequestError
failed to build route-aware request: {0}
Error message
failed to build route-aware request: {0} What it means
RouteAwareRequestError::Build is stored by RouteAwareRequestBuilder when a builder method cannot prepare the request: .header() records the http::Error string for an invalid header name or value (route_aware_client_pool.rs:246) and .json() records the serde_json::to_vec error string (route_aware_client_pool.rs:281). send() then yields it via 'self.request?' (line 312). It is deterministic: nothing network-related is involved, so retrying cannot succeed.
Source
Thrown at codex-rs/http-client/src/route_aware_client_pool.rs:94
}
/// 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,
#[error("route-aware request timed out")]
Timeout,
}
impl RouteAwareRequestError {
/// Classifies transport, proxy, and certificate failures without exposing request details.
pub fn failure_class(&self) -> Option<RouteFailureClass> {
if self.is_timeout() {
return Some(RouteFailureClass::ConnectTimeout);
}
if self.status() == Some(StatusCode::PROXY_AUTHENTICATION_REQUIRED) {
return Some(RouteFailureClass::ProxyAuthenticationRequired);
}View on GitHub (pinned to 339751715c)
Solutions
- Read the embedded string: it is the http::Error or serde_json::Error Display and names the offending part
- Validate header names and values before building: HeaderName::try_from / HeaderValue::try_from reject CR/LF and invalid bytes
- For JSON failures, fix or pre-serialize the payload with serde_json::to_vec and attach it with .body() so the error surfaces at your call site
- Reject the request as malformed input instead of retrying: the same input fails identically
Example fix
// before
let resp = pool.get(url).header("X-Trace", user_input).send().await?; // Build("invalid header value") on CR/LF
// after: validate at the boundary, reject early
let value = http::HeaderValue::from_str(&user_input)
.map_err(|e| BadRequest::invalid_header(e))?;
let resp = pool.get(url).header("X-Trace", value).send().await?; Defensive patterns
Strategy: validation
Validate before calling
// Validate header parts exactly as the builder will
fn header_parts_valid(name: &str, value: &str) -> bool {
http::HeaderName::try_from(name).is_ok() && http::HeaderValue::try_from(value).is_ok()
}
// Pre-serialize JSON so failures surface at your call site
fn json_body(value: &impl Serialize) -> Result<Vec<u8>, String> {
serde_json::to_vec(value).map_err(|e| e.to_string())
} Type guard
fn is_request_build_error(e: &RouteAwareRequestError) -> bool {
matches!(e, RouteAwareRequestError::Build(_))
} Try / catch
Err(RouteAwareRequestError::Build(reason)) => {
// deterministic bad input: reject, never retry
return Err(BadRequest::malformed(reason));
} Prevention
- Reject CR/LF and control bytes in any user-controlled header value before it reaches .header()
- Validate header names against an allowlist when they come from config
- Pre-serialize JSON payloads at the boundary to keep serialization errors in your own error type
- Fuzz header-heavy request paths; builder errors surface at send time, which is late
When it happens
Trigger: Calling pool.post(url).header(name, value) where the name contains invalid characters (spaces, non-ASCII) or the value contains control characters/newlines (CRLF injection), or .json(&value) where the value's Serialize impl returns an error during serde_json::to_vec.
Common situations: Passing user- or config-supplied strings straight into header values without sanitization, dynamic header names built from templates, custom Serialize types that error on edge-case data (NaN sentinels, exhausted state).
Related errors
- Agent Identity only supports production and staging ChatGPT
- failed to decrypt encrypted task id
- approval_policy = "untrusted" is no longer supported; remove
- invalid remote control account id header: {err}
- invalid patch: {0}
AI-assisted analysis of openai/codex@339751715c (2026-08-25).
Data as JSON: /api/errors/4039729206bb4a35.
Report an issue: GitHub.