hasura/graphql-engine · error · WebSocketError

{SEC_WEBSOCKET_PROTOCOL} header: {0}

Error message

{SEC_WEBSOCKET_PROTOCOL} header: {0}

What it means

The `Sec-WebSocket-Protocol` header was present but its value could not be interpreted; specifically the header value failed conversion to a string (`ToStrError` from the http crate), usually because it contains non-visible-ASCII bytes. Reported as `WebSocketError::InvalidHeaderValue` during the upgrade handshake.

Source

Thrown at v3/crates/graphql/graphql-ws/src/websocket/mod.rs:118

                        .insert(SEC_WEBSOCKET_ID, websocket_id.to_string().parse()?);
                    Ok(response)
                })
            },
        );

        result.unwrap_or_else(IntoResponse::into_response)
    }
}

/// Error types for WebSocket connections.
#[derive(Debug, thiserror::Error)]
pub enum WebSocketError {
    /// Error when the Sec-WebSocket-Protocol header is missing
    #[error("Missing {SEC_WEBSOCKET_PROTOCOL} header")]
    MissingProtocolHeader,

    /// Error when the header value cannot be converted to a string
    #[error("{SEC_WEBSOCKET_PROTOCOL} header: {0}")]
    InvalidHeaderValue(#[from] ToStrError),

    /// Error when the GraphQL WebSocket protocol is not included
    #[error("Expecting {} protocol", protocol::GRAPHQL_WS_PROTOCOL)]
    ExpectingGraphqlWsProtocol,

    /// Error when setting the WebSocket ID header value fails in response
    #[error("Unable to set {SEC_WEBSOCKET_ID} header value: {0}")]
    WebSocketIdInvalidHeaderValue(#[from] InvalidHeaderValue),
}

impl tracing_util::TraceableError for WebSocketError {
    fn visibility(&self) -> tracing_util::ErrorVisibility {
        match self {
            Self::MissingProtocolHeader
            | Self::ExpectingGraphqlWsProtocol
            | Self::InvalidHeaderValue(_) => tracing_util::ErrorVisibility::User,
            Self::WebSocketIdInvalidHeaderValue(_) => tracing_util::ErrorVisibility::Internal,

View on GitHub (pinned to 724551b9ae)

Solutions

  1. Capture the raw upgrade request to inspect the exact Sec-WebSocket-Protocol bytes
  2. Fix the client/intermediary to send a plain ASCII value such as `graphql-transport-ws`
  3. Remove or repair any proxy transform that rewrites the header
  4. If handcrafting handshakes, validate the header is visible-ASCII before sending

Example fix

# before (curl, accidental raw bytes)
curl -H $'Sec-WebSocket-Protocol: graphql-transport-ws\x0b' ...
# after
curl -H 'Sec-WebSocket-Protocol: graphql-transport-ws' ...
Defensive patterns

Strategy: validation

Validate before calling

const proto = 'graphql-transport-ws';
if (!/^[\x21-\x7e]+$/.test(proto)) throw new Error('bad protocol header');

Try / catch

catch (e) { if (String(e).includes('Sec-WebSocket-Protocol')) { inspect raw header bytes; resend with ASCII value; } }

Prevention

When it happens

Trigger: A client or intermediary sends a Sec-WebSocket-Protocol header value containing bytes outside visible ASCII (control characters, non-ASCII encoding), causing `to_str()` on the header value to fail when the server parses the subprotocol list.

Common situations: Malformed handcrafted WS clients; middleware or proxies that mangle header encoding (e.g. UTF-16 leaking in); corrupted header injection in test harnesses; rarely, a badly encoded library default protocol string.

Related errors


AI-assisted analysis of hasura/graphql-engine@724551b9ae (2026-08-28). Data as JSON: /api/errors/ae42071de0ebba1c. Report an issue: GitHub.