actix/actix-web · critical

Invalid header value

Error message

Invalid header value

What it means

The deprecated `DefaultHeaders::header()` helper at actix-web/src/middleware/default_headers.rs:92-95 converts the value with `HeaderValue::try_from` and `.expect("Invalid header value")`. Values containing illegal bytes (e.g. control characters, a raw newline `\n`) panic.

Source

Thrown at actix-web/src/middleware/default_headers.rs:94

    #[doc(hidden)]
    #[deprecated(
        since = "4.0.0",
        note = "Prefer `.add((key, value))`. Will be removed in v5."
    )]
    pub fn header<K, V>(self, key: K, value: V) -> Self
    where
        HeaderName: TryFrom<K>,
        <HeaderName as TryFrom<K>>::Error: Into<HttpError>,
        HeaderValue: TryFrom<V>,
        <HeaderValue as TryFrom<V>>::Error: Into<HttpError>,
    {
        self.add((
            HeaderName::try_from(key)
                .map_err(Into::into)
                .expect("Invalid header name"),
            HeaderValue::try_from(value)
                .map_err(Into::into)
                .expect("Invalid header value"),
        ))
    }

    /// Adds a default *Content-Type* header if response does not contain one.
    ///
    /// Default is `application/octet-stream`.
    pub fn add_content_type(self) -> Self {
        #[allow(clippy::declare_interior_mutable_const)]
        const HV_MIME: HeaderValue = HeaderValue::from_static("application/octet-stream");
        self.add((CONTENT_TYPE, HV_MIME))
    }
}

impl<S, B> Transform<S, ServiceRequest> for DefaultHeaders
where
    S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
    S::Future: 'static,
{

View on GitHub (pinned to 937960ca67)

Solutions

  1. Use the `.add((name, value))` API and validate the value first, handling the error.
  2. Strip or reject CR/LF and other control bytes from any dynamic value.
  3. For ASCII-only values, consider percent-encoding or base64-encoding binary data.

Example fix

// before
mw.header("X-Test", user_input); // panics if user_input has \n

// after
fn try_add(mw: DefaultHeaders, v: &str) -> Result<DefaultHeaders, actix_web::Error> {
    let val = HeaderValue::try_from(v)?;
    Ok(mw.add(("X-Test", val)))
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate header values; reject CR/LF and control bytes.
use actix_web::http::header::HeaderValue;
fn valid_value(v: &str) -> bool {
    HeaderValue::try_from(v).is_ok()
}
// assert!(!valid_value("\n"));
// assert!(valid_value("ok"));

Type guard

fn is_valid_header_value(v: &str) -> bool {
    !v.bytes().any(|b| b == b'\r' || b == b'\n' || b.is_ascii_control())
        && HeaderValue::try_from(v).is_ok()
}

Prevention

When it happens

Trigger: Calling `.header("X-Test", "\n")` or passing user input containing CR/LF or other forbidden bytes.

Common situations: Embedding untrusted strings into a header value without sanitization (header injection risk).

Related errors


AI-assisted analysis of actix/actix-web@937960ca67 (2026-08-06). Data as JSON: /data/errors/57daefdab67a0ae0.json. Report an issue: GitHub.