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
- Set the subprotocol on the client: new WebSocket(url, 'graphql-ws') or the equivalent option in your GraphQL WS client library
- Verify no proxy between client and server strips the Sec-WebSocket-Protocol header
- 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
- Always pass 'graphql-ws' as the WebSocket subprotocol when constructing the client
- Use a maintained GraphQL WS client library rather than raw sockets
- Test WebSocket connections through the same proxy configuration as production
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
- Unable to parse WebSocket message: {0}
- subscription are not supported over HTTP
- Connection already initialized
- Invalid header name: {0}
- Connection initialization timed out
AI-assisted analysis of hasura/graphql-engine@724551b9ae (2026-08-28).
Data as JSON: /api/errors/fff6f829c002ec11.
Report an issue: GitHub.