seanmonstar/reqwest · error · reqwest::Error

HTTP/3 only supports 'https' or 'h3' schemes, got: {}

Error message

HTTP/3 only supports 'https' or 'h3' schemes, got: {}

What it means

Raised by `extract_domain` in the HTTP/3 pool (pool.rs:369-379) when a request URI's scheme is neither `https` nor `h3`. HTTP/3 mandates TLS 1.3 over QUIC, so plaintext schemes are rejected up front before any connection is attempted.

Source

Thrown at src/async_impl/h3_client/pool.rs:374

        if let Some(content_length) = self.content_length {
            hyper::body::SizeHint::with_exact(content_length)
        } else {
            hyper::body::SizeHint::default()
        }
    }
}

pub(crate) fn extract_domain(uri: &mut Uri) -> Result<Key, Error> {
    let uri_clone = uri.clone();
    match (uri_clone.scheme(), uri_clone.authority()) {
        (Some(scheme), Some(auth)) => {
            let scheme_str = scheme.as_str();
            if scheme_str != "https" && scheme_str != "h3" {
                return Err(Error::new(
                    Kind::Request,
                    Some(Box::new(std::io::Error::new(
                        std::io::ErrorKind::InvalidInput,
                        format!(
                            "HTTP/3 only supports 'https' or 'h3' schemes, got: {}",
                            scheme_str
                        ),
                    ))),
                ));
            }
            Ok((scheme.clone(), auth.clone()))
        }
        _ => Err(Error::new(Kind::Request, None::<Error>)),
    }
}

pub(crate) fn domain_as_uri((scheme, auth): Key) -> Uri {
    http::uri::Builder::new()
        .scheme(scheme)
        .authority(auth)
        .path_and_query("/")
        .build()

View on GitHub (pinned to 17e9bcb51c)

Solutions

  1. Use an `https://` (or `h3://`) URL for any request going through the HTTP/3 client.
  2. Do not set `.http3_only()` if you need to reach plaintext `http://` endpoints; drop to `.http3_prior_knowledge()` only on known h3 hosts, or use a plain client for http.
  3. Validate the URL scheme before dispatch when scheme is user-supplied.

Example fix

// before
let client = Client::builder().http3_only().build()?;
let r = client.get("http://api.example.com").send().await?; // rejected

// after
let url = if !url.starts_with("https://") { format!("https://{url}") } else { url };
let r = client.get(url).send().await?;
Defensive patterns

Strategy: validation

Validate before calling

fn h3_url_ok(u: &str) -> bool {
    u.starts_with("https://") || u.starts_with("h3://")
}
// guard
if !h3_url_ok(&url) { return Err(anyhow!("h3 requires https:// or h3://")); }

Type guard

fn is_h3_bad_scheme(e: &reqwest::Error) -> bool {
    e.is_request()
        && e.source().map(|s| s.to_string().contains("HTTP/3 only supports")).unwrap_or(false)
}

Try / catch

let resp = client.get(&url).send().await.map_err(|e| {
    if is_h3_bad_scheme(&e) { anyhow::anyhow!("use https:// for h3 client") } else { e.into() }
})?;

Prevention

When it happens

Trigger: Calling an HTTP/3 client (built with the `http3` feature) against a `http://` URL, a `ws://` URL, or any custom scheme like `ftp://`. Also when a request is manually constructed with `Request::builder().uri("http://...")` and dispatched through the h3 service.

Common situations: Developer enables `http3_only()` but still hits `http://` dev URLs (e.g. localhost); configuration loaded scheme dynamically and the http fallback path wasn't wired; mixed redirect chain where a redirect target is `http://`.

Related errors


AI-assisted analysis of seanmonstar/reqwest@17e9bcb51c (2026-08-06). Data as JSON: /data/errors/23cfb8016bdd1fc9.json. Report an issue: GitHub.