seanmonstar/reqwest · error · BadScheme
URL scheme is not allowed
Error message
URL scheme is not allowed
What it means
The BadScheme struct (src/error.rs:432-441) displays as 'URL scheme is not allowed' and is raised by url_bad_scheme() (src/error.rs:387-389) as a Kind::Builder error carrying the offending Url. It is produced at three sites: IntoUrl::into_url() when a parsed Url has no host (src/into_url.rs:34-38), Client::execute_request() when the scheme is not http or https, or when https_only mode rejects an http URL (src/async_impl/client.rs:2622-2629), and the redirect policy when a Location header points to a non-http(s) scheme (src/redirect.rs:320-328). reqwest intentionally restricts transport to http/https; file, ftp, data, blob, ws schemes are rejected.
Solutions
- Use an absolute http:// or https:// URL with a host: prepend the scheme and host to relative paths before calling reqwest.
- If you enabled .https_only(true), either disable it or change the target URL to https://.
- For file:// resources use std::fs / tokio::fs instead of reqwest; for data: URIs parse them directly.
- Configure a redirect::Policy::none() or a custom policy that stops on cross-scheme redirects instead of erroring, if a server may redirect to a non-http(s) Location.
Example fix
// before
let resp = reqwest::get("/api/v1/users").await?;
// after
let base = std::env::var("API_BASE").unwrap_or_else(|_| "https://api.example.com".into());
let resp = reqwest::get(format!("{base}/api/v1/users")).await?; Defensive patterns
Strategy: validation
Validate before calling
fn validate_reqwest_url(raw: &str) -> Result<url::Url, String> {
let url = url::Url::parse(raw).map_err(|e| format!("invalid URL: {e}"))?;
if !url.has_host() {
return Err("URL must have a host".into());
}
match url.scheme() {
"http" | "https" => Ok(url),
other => Err(format!("scheme '{other}' not allowed by reqwest")),
}
}
let url = validate_reqwest_url(&raw)?;
let resp = reqwest::get(url).await?; Type guard
fn is_transport_scheme(url: &url::Url) -> bool {
url.has_host() && matches!(url.scheme(), "http" | "https")
} Try / catch
match reqwest::get(url).await {
Ok(resp) => { /* ... */ }
Err(e) => {
if e.is_builder()
&& e.source().map(|s| s.to_string()).as_deref() == Some("URL scheme is not allowed")
{
// reject the input URL as unsupported transport
} else {
return Err(e);
}
}
} Prevention
- Always pass absolute http(s) URLs with a host; reject bare paths at the input boundary.
- Keep https_only() consistent with the schemes you actually request.
- When following user-controlled redirects, set a custom Policy that rejects cross-scheme Location values up front.
When it happens
Trigger: Calling reqwest::get("file:///etc/hosts"), get("data:text/plain,hi"), get("ftp://host"), get("blob:https://...") (non-wasm), or a bare relative path like get("/api/v1") with no host. Setting .https_only(true) on the builder and then requesting an http:// URL. Following a redirect whose Location is a non-http(s) URI (e.g. a server redirecting to an app:// deep link or data: URI). On non-wasm, passing a host-less Url through IntoUrl.
Common situations: Reading a URL from an env var or config file that was set to a file:// path during local dev. Putting a relative path in a base-URL variable. Mixed-content: an https-only client pointed at an http upstream behind a proxy. A server returning a cross-scheme redirect (https -> app deep link). Test fixtures using data: URIs.
Related errors
- HTTP/3 only supports 'https' or 'h3' schemes, got
- Client::new()
- Client::new()
- Parsed Url is not a valid Uri
AI-assisted analysis of seanmonstar/reqwest@9f06fd28ab (2026-08-10).
Data as JSON: /api/errors/f97a850abae2bbd0.
Report an issue: GitHub.
Appendix: source
Thrown at src/error.rs:388
status: StatusCode,
#[cfg(not(all(target_arch = "wasm32", any(target_os = "unknown", target_os = "none"))))] reason: Option<hyper::ext::ReasonPhrase>,
) -> Error {
Error::new(
Kind::Status(
status,
#[cfg(not(all(
target_arch = "wasm32",
any(target_os = "unknown", target_os = "none")
)))]
reason,
),
None::<Error>,
)
.with_url(url)
}
pub(crate) fn url_bad_scheme(url: Url) -> Error {
Error::new(Kind::Builder, Some(BadScheme)).with_url(url)
}
pub(crate) fn url_invalid_uri(url: Url) -> Error {
Error::new(Kind::Builder, Some("Parsed Url is not a valid Uri")).with_url(url)
}
if_wasm! {
pub(crate) fn wasm(js_val: wasm_bindgen::JsValue) -> BoxError {
format!("{js_val:?}").into()
}
}
pub(crate) fn upgrade<E: Into<BoxError>>(e: E) -> Error {
Error::new(Kind::Upgrade, Some(e))
}
// io::Error helpers
View on GitHub (pinned to 9f06fd28ab)