leptos-rs/leptos · error

Failed to create HeaderValue

Error message

Failed to create HeaderValue

What it means

The actix integration's `redirect()` inserts the `Location` header by converting the target path with `actix_http::header::HeaderValue::from_str(path)` and `.expect()`ing success. `HeaderValue::from_str` fails when the string contains bytes outside visible ASCII range (0x20–0x7E, plus it rejects DEL and control chars), so a redirect target with non-ASCII or control characters panics the server function.

Source

Thrown at integrations/actix/src/lib.rs:237

/// header contains `text/html` as it does for an ordinary navigation.)
///
/// Otherwise, it sets a custom header that indicates to the client that it should redirect,
/// without actually setting the status code. This means that the client will not follow the
/// redirect, and can therefore return the value of the server function and then handle
/// the redirect with client-side routing.
#[cfg_attr(
    feature = "tracing",
    tracing::instrument(level = "trace", fields(error), skip_all)
)]
pub fn redirect(path: &str) {
    if let (Some(req), Some(res)) =
        (use_context::<Request>(), use_context::<ResponseOptions>())
    {
        // insert the Location header in any case
        res.insert_header(
            header::LOCATION,
            header::HeaderValue::from_str(path)
                .expect("Failed to create HeaderValue"),
        );

        let accepts_html = req
            .headers()
            .get(ACCEPT)
            .and_then(|v| v.to_str().ok())
            .map(|v| v.contains("text/html"))
            .unwrap_or(false);
        if accepts_html {
            // if the request accepts text/html, it's a plain form request and needs
            // to have the 302 code set
            res.set_status(StatusCode::FOUND);
        } else {
            // otherwise, we sent it from the server fn client and actually don't want
            // to set a real redirect, as this will break the ability to return data
            // instead, set the REDIRECT_HEADER to indicate that the client should redirect
            res.insert_header(
                HeaderName::from_static(REDIRECT_HEADER),

View on GitHub (pinned to 32d20f6c9d)

Solutions

  1. Percent-encode the path before calling redirect (e.g. `url::Url::parse` + `to_string`, or `utf8_percent_encode(path, NON_ALPHANUMERIC)` / `encode` from `leptos`'s or `form_urlencoded` utilities)
  2. Validate/sanitize user-supplied redirect targets (allow only ASCII printable, absolute paths) before redirecting
  3. Return a typed error instead of calling redirect when the target fails `HeaderValue::from_str`-style validation
  4. Keep Location values as ASCII: encode the path component, keep query strings encoded via `serde_urlencoded`

Example fix

// before
redirect(&format!("/users/{}", user_display_name)); // may contain non-ASCII
// after
use url::form_urlencoded;
let encoded: String = form_urlencoded::byte_serialize(user_display_name.as_bytes()).collect();
redirect(&format!("/users/{}", encoded));
Defensive patterns

Strategy: validation

Validate before calling

fn is_valid_location(path: &str) -> bool {
    !path.is_empty()
        && path.bytes().all(|b| (0x20..=0x7e).contains(&b))
        && path.starts_with('/')
}

if !is_valid_location(&target) {
    // reject or percent-encode before calling redirect
}

Prevention

When it happens

Trigger: Calling `leptos_actix::redirect("...")` with a path/URL containing non-ASCII characters (e.g. unencoded CJK or accented characters), newlines, or other control characters.

Common situations: Redirecting to a URL built from user input (usernames, search queries, localized slugs) without percent-encoding; logging/teardown paths that embed multiline data; i18n routes where the localized segment wasn't URL-encoded.

Related errors


AI-assisted analysis of leptos-rs/leptos@32d20f6c9d (2026-09-01). Data as JSON: /api/errors/89eae4c586ff2175. Report an issue: GitHub.