{"record":{"id":"e9c0991e61707c4b","repo":"openai/codex","slug":"redirect-target-uses-unsupported-url-scheme-0","errorCode":null,"errorMessage":"redirect target uses unsupported URL scheme: {0}","messagePattern":"redirect target uses unsupported URL scheme: (.+?)","errorType":"exception","errorClass":"RouteAwareRequestError","httpStatus":null,"severity":"error","filePath":"codex-rs/http-client/src/route_aware_client_pool.rs","lineNumber":96,"sourceCode":"/// Error returned when selecting a route or constructing its pooled HTTP client.\n#[derive(Debug, thiserror::Error)]\npub enum RouteAwareClientPoolError {\n    #[error(\"failed to resolve the outbound proxy route: {0}\")]\n    Resolve(#[source] io::Error),\n    #[error(transparent)]\n    Build(#[from] BuildRouteAwareHttpClientError),\n}\n\n/// Error returned while building, routing, or sending a route-aware request.\n#[derive(Debug, thiserror::Error)]\npub enum RouteAwareRequestError {\n    #[error(transparent)]\n    Request(#[from] reqwest::Error),\n    #[error(transparent)]\n    Route(#[from] RouteAwareClientPoolError),\n    #[error(\"failed to build route-aware request: {0}\")]\n    Build(String),\n    #[error(\"redirect target uses unsupported URL scheme: {0}\")]\n    UnsupportedRedirectScheme(String),\n    #[error(\"too many redirects\")]\n    TooManyRedirects,\n    #[error(\"route-aware request timed out\")]\n    Timeout,\n}\n\nimpl RouteAwareRequestError {\n    /// Classifies transport, proxy, and certificate failures without exposing request details.\n    pub fn failure_class(&self) -> Option<RouteFailureClass> {\n        if self.is_timeout() {\n            return Some(RouteFailureClass::ConnectTimeout);\n        }\n        if self.status() == Some(StatusCode::PROXY_AUTHENTICATION_REQUIRED) {\n            return Some(RouteFailureClass::ProxyAuthenticationRequired);\n        }\n        if let Self::Route(RouteAwareClientPoolError::Resolve(error)) = self\n            && let Some(source) = error.get_ref()","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/openai/codex/blob/339751715c64496cb86246bfb3935f40e309dd3d/codex-rs/http-client/src/route_aware_client_pool.rs#L78-L114","documentation":"RouteAwareRequestError::UnsupportedRedirectScheme is raised during the pool's manual redirect following (route_aware_client_pool.rs:635-639). Under RespectSystemProxy (or TLS-backend fallback) reqwest's internal redirects are disabled so each hop gets its own route decision; when a 301/302/303/307/308 Location resolves to a URL whose scheme is not http or https, the pool refuses to follow and returns this error with the offending scheme as its string.","triggerScenarios":"Sending through a RouteAwareClientPool that follows redirects manually when the server answers 3xx with Location: ftp://..., file://..., or any non-http(s) URI: the scheme check at route_aware_client_pool.rs:635 fails and the send aborts instead of following the hop.","commonSituations":"Legacy download endpoints still redirecting to ftp://, misconfigured server or CDN redirect rules, open-redirect probes pointing at exotic schemes, local dev servers redirecting to internal tooling URLs.","solutions":["Trace the redirect chain (curl -IL) and fix the server's Location target to an http/https URL","If the target scheme is legitimately outside HTTP, handle it at the application layer instead of expecting the pool to follow it","Use a pool built with RouteAwareClientPool::new_without_redirects so each 3xx response is returned to your code and you decide which hops to follow","Do not retry: the same Location will fail identically"],"exampleFix":"// before\nlet pool = RouteAwareClientPool::new(factory, ClientRouteClass::Api);\nlet resp = pool.get(url).send().await?; // UnsupportedRedirectScheme(\"ftp\")\n\n// after: observe redirects yourself and follow only http/https\nlet pool = RouteAwareClientPool::new_without_redirects(factory, ClientRouteClass::Api);\nlet resp = pool.get(url).send().await?;\nif resp.status().is_redirection() { /* read Location, decide, re-send */ }","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"fn is_unsupported_redirect(e: &RouteAwareRequestError) -> bool {\n    matches!(e, RouteAwareRequestError::UnsupportedRedirectScheme(_))\n}","tryCatchPattern":"Err(RouteAwareRequestError::UnsupportedRedirectScheme(scheme)) => {\n    // surface the original destination; do not follow non-HTTP schemes\n    Err(Upstream::RedirectScheme { scheme, from: original_url })\n}","preventionTips":["When URLs (or proxies that rewrite them) are user-configurable, validate the redirect chain's schemes up front","Prefer a no-redirect pool plus explicit hop handling when redirect targets are untrusted","Remember RespectSystemProxy pools follow redirects manually: reqwest's default redirect policy does not apply","Integration-test redirect-heavy flows so scheme changes on the server fail in CI, not production"],"tags":["http","redirect","url","rust"],"backgroundTag":"unsupported-redirect-scheme","analyzedSha":"339751715c64496cb86246bfb3935f40e309dd3d","analyzedAt":"2026-08-25T05:35:09.876Z","schemaVersion":2},"datasetVersion":"2026-08-25T06:17:31.827Z"}