hasura/graphql-engine · error · WebSocketError
Missing {SEC_WEBSOCKET_PROTOCOL} header
Error message
Missing {SEC_WEBSOCKET_PROTOCOL} header What it means
The WebSocket upgrade request lacked the `Sec-WebSocket-Protocol` HTTP header, which is required because the graphql-ws server negotiates the `graphql-transport-ws` subprotocol. Without this header the server cannot confirm the client speaks the expected protocol and rejects the connection with `WebSocketError::MissingProtocolHeader`.
Source
Thrown at v3/crates/graphql/graphql-ws/src/websocket/mod.rs:114
});
// Set the WebSocket id response header
response
.headers_mut()
.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 {View on GitHub (pinned to 724551b9ae)
Solutions
- Pass the subprotocol when connecting: `new WebSocket(url, 'graphql-transport-ws')`
- If behind a proxy, configure it to forward the Sec-WebSocket-Protocol header on upgrades
- Verify with a raw handshake dump (curl -H 'Sec-WebSocket-Protocol: graphql-transport-ws' ... or wireshark) that the header reaches the server
- Upgrade client libs that are known to drop the header
Example fix
// before
const ws = new WebSocket('wss://api.example.com/graphql');
// after
const ws = new WebSocket('wss://api.example.com/graphql','graphql-transport-ws'); Defensive patterns
Strategy: validation
Validate before calling
const ws = new WebSocket(url, 'graphql-transport-ws'); // always pass the protocol
Try / catch
catch (e) { if (String(e).includes('Missing') && String(e).includes('header')) { reconnect with subprotocol; } } Prevention
- Always specify the subprotocol in the WebSocket constructor
- Configure proxies to forward Sec-WebSocket-Protocol
- Smoke-test the handshake in CI
When it happens
Trigger: Opening a WebSocket to the graphql endpoint without specifying a subprotocol — e.g. `new WebSocket(url)` with no protocols argument, or a raw client that omits the header. The server inspects the upgrade request's Sec-WebSocket-Protocol header and fails when absent.
Common situations: Using a generic WS client or curl-based test that omits subprotocols; a proxy (nginx/envoy) stripping the Sec-WebSocket-Protocol header; client library upgrade that stopped sending protocols; browser clients forgetting the second WebSocket constructor argument.
Related errors
- {SEC_WEBSOCKET_PROTOCOL} header: {0}
- Connection already initialized
- Invalid header value: {0}
- AuthError: {0}
- SessionError: {0}
AI-assisted analysis of hasura/graphql-engine@724551b9ae (2026-08-28).
Data as JSON: /api/errors/f18bd4e3b33ff8be.
Report an issue: GitHub.