DioxusLabs/dioxus · error

protocols is an invalid header value

Error message

protocols is an invalid header value

What it means

The fullstack WebSocket client builds its RFC 6455 handshake manually and writes Sec-WebSocket-Protocol via HeaderValue::from_str(protocols.join(", ")). from_str rejects any byte outside visible ASCII (control characters, newlines, tabs, and all non-ASCII UTF-8 such as emoji or accented letters), so one malformed subprotocol name makes the expect panic.

Source

Thrown at packages/fullstack/src/payloads/websocket.rs:1261

                    HeaderValue::from_static("upgrade"),
                );
                headers.insert(
                    reqwest::header::UPGRADE,
                    HeaderValue::from_static("websocket"),
                );
                headers.insert(
                    reqwest::header::SEC_WEBSOCKET_KEY,
                    HeaderValue::from_str(&nonce_value).expect("nonce is a invalid header value"),
                );
                headers.insert(
                    reqwest::header::SEC_WEBSOCKET_VERSION,
                    HeaderValue::from_static("13"),
                );
                if !protocols.is_empty() {
                    headers.insert(
                        reqwest::header::SEC_WEBSOCKET_PROTOCOL,
                        HeaderValue::from_str(&protocols.join(", "))
                            .expect("protocols is an invalid header value"),
                    );
                }

                Some(nonce_value)
            }
            Version::HTTP_2 => {
                // TODO: Implement websocket upgrade for HTTP 2.
                return Err(HandshakeError::UnsupportedHttpVersion(version).into());
            }
            _ => {
                return Err(HandshakeError::UnsupportedHttpVersion(version).into());
            }
        };

        // execute request
        let response = client.execute(request).await?;

        Ok(WebSocketResponse {

View on GitHub (pinned to 393d190a80)

Solutions

  1. Restrict subprotocol names to RFC 6455 token characters: ASCII letters, digits, and - _ . + ~ ! $ & ' ( ) * + , ; = as appropriate tokens
  2. Sanitize/validate protocol strings before passing them to the WebSocket configuration
  3. URL-encode or hash any dynamic value embedded in a protocol name

Example fix

// before
ws.subprotocol(format!("auth-{token}")); // token contains non-ASCII -> panic
// after
ws.subprotocol(format!("auth-{}", simple_hash(&token))); // ASCII-only name
Defensive patterns

Strategy: validation

Validate before calling

fn is_valid_subprotocol(p: &str) -> bool {
    !p.is_empty()
        && p.bytes().all(|b| (0x21..=0x7e).contains(&b) && b != b',') // visible ASCII, no delimiter
        && !p.starts_with(' ')
}
assert!(protocols.iter().all(|p| is_valid_subprotocol(p)));

Type guard

fn valid_subprotocols<'a>(ps: impl IntoIterator<Item = &'a str>) -> Option<String> {
    let joined = ps.into_iter().collect::<Vec<_>>().join(", ");
    joined.bytes().all(|b| (0x20..=0x7e).contains(&b)).then_some(joined)
}

Prevention

When it happens

Trigger: Configuring the WebSocket client with .subprotocol(...) entries containing non-ASCII or control characters — newlines, tabs, emoji, non-latin scripts — or programmatically composed protocol strings that embed unvalidated user input.

Common situations: Passing auth tokens, locale names, or free-form user strings as subprotocols; copy-pasting protocol names containing invisible unicode; joining protocols that already contain commas/whitespace.

Related errors


AI-assisted analysis of DioxusLabs/dioxus@393d190a80 (2026-08-16). Data as JSON: /api/errors/25a82462c3d2d554. Report an issue: GitHub.