hasura/graphql-engine · error · WebSocketError

Expecting {} protocol

Error message

Expecting {} protocol

What it means

This error is thrown by the graphql-ws WebSocket handler when a client attempts to connect without requesting the expected GraphQL over WebSocket subprotocol (the Sec-WebSocket-Protocol header does not include the graphql-ws protocol string). The server rejects the upgrade because it can only speak the graphql-ws protocol. It is part of the connection negotiation errors in the websocket module.

Source

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

        );

        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. Set the subprotocol on the client: new WebSocket(url, 'graphql-ws') or the equivalent option in your GraphQL WS client library
  2. Verify no proxy between client and server strips the Sec-WebSocket-Protocol header
  3. If you must support legacy clients, use a client that speaks the graphql-ws protocol (e.g. graphql-ws npm package instead of subscriptions-transport-ws)

Example fix

// before
const ws = new WebSocket('wss://example.com/graphql');

// after
const ws = new WebSocket('wss://example.com/graphql', 'graphql-ws');
Defensive patterns

Strategy: validation

Validate before calling

const ws = new WebSocket(url, 'graphql-ws');
if (!['graphql-ws'].includes(ws.protocol)) {
  throw new Error(`Unexpected subprotocol: ${{ws.protocol}}`);
}

Type guard

function hasGraphqlWsProtocol(ws: WebSocket): boolean {{
  return ws.protocol === 'graphql-ws';
}}

Prevention

When it happens

Trigger: Opening a WebSocket connection to the GraphQL endpoint with a client that does not set Sec-WebSocket-Protocol: graphql-ws (e.g. a raw ws library, a wrong protocol name like graphql-ws old 'subscriptions-transport-ws', or a proxy that strips the subprotocol header).

Common situations: Using a generic WebSocket client instead of a GraphQL WS client; version mismatches where the client uses the older 'graphiql-transport-ws'/'subscriptions-transport-ws' protocol; reverse proxies (nginx, API gateways) dropping the Sec-WebSocket-Protocol header.

Related errors


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