seanmonstar/warp · warning
not_found
Error message
not_found
What it means
warp::host::exact (src/filters/host.rs:28) rejects with 404 not_found when the request's Authority (Host header / authority) does not equal the expected string. The filter extracts the authority via host::optional() and, unless it matches exactly, returns reject::not_found(). Panics at construction if the expected string is not a valid authority.
Solutions
- Match the exact authority including port: warp::host::exact("example.com:443") when requests carry a port
- Configure the reverse proxy to pass the original Host through (nginx: proxy_set_header Host $host;)
- Use host::optional() yourself and compare only the host part if you want port-insensitive matching
- Remove or relax the host filter if vhost discrimination is not actually needed
- Test with curl -H "Host: example.com" to confirm the filter matches the intended value
Example fix
// before
let routes = warp::host::exact("example.com").and(api());
// after (accept both bare host and host:port)
let routes = warp::host::optional()
.and_then(|opt: Option<http::uri::Authority>| async move {
match opt {
Some(a) if a.host() == "example.com" => Ok(()),
_ => Err(warp::reject::not_found()),
}
})
.untuple_one()
.and(api()); Defensive patterns
Strategy: validation
Validate before calling
// verify what authority the server actually receives curl -s -o /dev/null -D - -H "Host: example.com:443" https://api.example.com/route // compare against the exact string passed to warp::host::exact
Type guard
fn host_matches(authority: &http::uri::Authority, expected_host: &str) -> bool {
authority.host() == expected_host
} Try / catch
let route = warp::host::exact("example.com")
.and(api())
.recover(|rej: warp::Rejection| async move {
if rej.is_not_found() {
Ok(warp::reply::with_status("unknown host", warp::http::StatusCode::NOT_FOUND))
} else {
Err(rej)
}
}); Prevention
- Include the port in host::exact when clients send one (e.g. ":443")
- Set proxy_set_header Host $host; in nginx or equivalent in other proxies
- Prefer comparing authority.host() for port-insensitive matching
- Add a startup test hitting the route with the production Host header
- Validate the expected string is a proper authority to avoid the construction panic
When it happens
Trigger: A request arrives whose Host header (including port) differs from the value passed to warp::host::exact("api.example.com") — e.g. host::exact("example.com") receiving "example.com:443", an internal IP, localhost, or a vhost mismatch through a reverse proxy.
Common situations: Behind nginx/ALB that forwards the upstream host instead of the original one (missing proxy_set_header Host); testing locally with localhost when the filter expects the production domain; forgetting the port in the expected authority; TLS/SNI mismatch; migrating domains without updating the filter.
Related errors
- method_not_allowed
- invalid host/authority
- CORS request forbidden
- invalid_header
- MissingConnectionUpgrade
AI-assisted analysis of seanmonstar/warp@ff34d7213e (2026-09-09).
Data as JSON: /api/errors/c5c358de4f5f02e0.
Report an issue: GitHub.
Appendix: source
Thrown at src/filters/host.rs:28
/// host and port) in the request.
///
/// Authority is specified either in the `Host` header or in the target URI.
///
/// # Example
///
/// ```
/// use warp::Filter;
///
/// let multihost =
/// warp::host::exact("foo.com").map(|| "you've reached foo.com")
/// .or(warp::host::exact("bar.com").map(|| "you've reached bar.com"));
/// ```
pub fn exact(expected: &str) -> impl Filter<Extract = (), Error = Rejection> + Clone {
let expected = Authority::from_str(expected).expect("invalid host/authority");
optional()
.and_then(move |option: Option<Authority>| match option {
Some(authority) if authority == expected => future::ok(()),
_ => future::err(reject::not_found()),
})
.untuple_one()
}
/// Creates a `Filter` that looks for an authority (target server's host
/// and port) in the request.
///
/// Authority is specified either in the `Host` header or in the target URI.
///
/// If found, extracts the `Authority`, otherwise continues the request,
/// extracting `None`.
///
/// Rejects with `400 Bad Request` if the `Host` header is malformed or if there
/// is a mismatch between the `Host` header and the target URI.
///
/// # Example
///
/// ```View on GitHub (pinned to ff34d7213e)