seanmonstar/warp · error

Origin is always a valid HeaderValue

Error message

Origin is always a valid HeaderValue

What it means

Cors::allow_origins converts each origin to a string and parses it as a HeaderValue, expecting success always ('Origin is always a valid HeaderValue'). This expect panics only if an origin string somehow isn't a valid header value — practically unreachable via valid Origin inputs, but reachable through the &str IntoOrigin path's own panics for malformed origins.

Solutions

  1. Pass bare origins like "https://example.com" without paths, queries, or trailing slashes
  2. Validate each origin string parses as an Origin before building the CORS layer
  3. Prefer allow_origins with typed Origin values where available

Example fix

// before
cors().allow_origins(&["https://example.com/api"])
// after
cors().allow_origins(&["https://example.com"])
Defensive patterns

Strategy: validation

Validate before calling

fn is_bare_origin(s: &str) -> bool {
    let mut parts = s.splitn(2, "://");
    parts.next().map_or(false, |sch| !sch.is_empty()) && parts.next().map_or(false, |rest| !rest.is_empty() && !rest.contains('/'))
}

Prevention

When it happens

Trigger: cors().allow_origins(&["bad origin"]) with strings failing Origin parsing (see allow_origin's 'missing scheme'/'invalid Origin' panics); direct panic at this line is nearly impossible with well-formed origins.

Common situations: Passing full URLs with paths ('https://x.com/path') or malformed origins to allow_origins; config entries that aren't bare origins.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


AI-assisted analysis of seanmonstar/warp@ff34d7213e (2026-09-09). Data as JSON: /api/errors/d5ebe4bb0d2248c9. Report an issue: GitHub.

Appendix: source

Thrown at src/filters/cors.rs:226

    /// Add multiple origins to the existing list of allowed `Origin`s.
    ///
    /// # Panics
    ///
    /// Panics if the provided argument is not a valid `Origin`.
    pub fn allow_origins<I>(mut self, origins: I) -> Self
    where
        I: IntoIterator,
        I::Item: IntoOrigin,
    {
        let iter = origins
            .into_iter()
            .map(IntoOrigin::into_origin)
            .map(|origin| {
                origin
                    .to_string()
                    .parse()
                    .expect("Origin is always a valid HeaderValue")
            });

        self.origins.get_or_insert_with(HashSet::new).extend(iter);

        self
    }

    /// Sets the `Access-Control-Max-Age` header.
    ///
    /// # Example
    ///
    ///
    /// ```
    /// use std::time::Duration;
    /// use warp::Filter;
    ///
    /// let cors = warp::cors()
    ///     .max_age(30) // 30u32 seconds

View on GitHub (pinned to ff34d7213e)