vllm-project/vllm · error

invalid --allowed-headers value {header:?}: {e}

Error message

invalid --allowed-headers value {header:?}: {e}

What it means

Thrown by CorsConfig::validate() when a --allowed-headers entry (other than "*") fails to parse as an http::HeaderName. Like the methods check, this is startup-time validation so the CORS layer can be constructed infallibly later. Header names must be valid HTTP token characters (no spaces, colons, or non-ASCII).

Source

Thrown at rust/src/server/src/config.rs:102

    pub fn validate(&self) -> Result<()> {
        for origin in &self.allow_origins {
            if origin != "*" {
                origin.parse::<HeaderValue>().map_err(|e| {
                    anyhow::anyhow!("invalid --allowed-origins value {origin:?}: {e}")
                })?;
            }
        }
        for method in &self.allow_methods {
            if method != "*" {
                method.parse::<Method>().map_err(|e| {
                    anyhow::anyhow!("invalid --allowed-methods value {method:?}: {e}")
                })?;
            }
        }
        for header in &self.allow_headers {
            if header != "*" {
                header.parse::<HeaderName>().map_err(|e| {
                    anyhow::anyhow!("invalid --allowed-headers value {header:?}: {e}")
                })?;
            }
        }
        Ok(())
    }
}

/// TLS settings mirroring Python's uvicorn `ssl_*` arguments.
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct TlsConfig {
    /// PEM certificate chain file. Required when TLS is configured; may also
    /// hold the private key (combined PEM) when `key_file` is unset.
    pub cert_file: Option<String>,
    /// PEM private key file. When `None`, the key is read from `cert_file`
    /// (combined PEM).
    pub key_file: Option<String>,
    /// PEM CA bundle used to verify client certificates (mTLS). Required when
    /// `cert_reqs` is non-zero.

View on GitHub (pinned to c794754062)

Solutions

  1. Pass each header as a separate, exact header name: --allowed-headers Content-Type --allowed-headers Authorization.
  2. Use "*" to allow all headers.
  3. Remove colons, commas, and whitespace from each entry.
  4. Inspect the {header:?} value in the error to find the offending entry.

Example fix

# before
--allowed-headers 'Content-Type, Authorization'

# after
--allowed-headers Content-Type --allowed-headers Authorization
# or
--allowed-headers '*'
Defensive patterns

Strategy: validation

Validate before calling

fn valid_headers(headers: &[String]) -> bool {
    headers.iter().all(|h| h == "*" || h.parse::<http::header::HeaderName>().is_ok())
}

Type guard

fn is_valid_header_list(headers: &[String]) -> bool {
    headers.iter().all(|h| h == "*" || h.parse::<http::header::HeaderName>().is_ok())
}

Prevention

When it happens

Trigger: Passing --allowed-headers with values like 'Content-Type:' (trailing colon), 'X Custom-Header' (space), 'content-type;' or a whole comma-joined list as a single entry. Any entry containing characters illegal in a header name (spaces, CTLs, non-token chars) fails Method/HeaderName parsing at boot.

Common situations: Porting an Access-Control-Allow-Headers value verbatim from a Python uvicorn/fastapi deployment ('Content-Type, Authorization' as one string), or including the header value instead of only the name.

Related errors


AI-assisted analysis of vllm-project/vllm@c794754062 (2026-08-14). Data as JSON: /api/errors/be45f66f50100e6d. Report an issue: GitHub.