{"record":{"id":"f18bd4e3b33ff8be","repo":"hasura/graphql-engine","slug":"missing-sec-websocket-protocol-header","errorCode":null,"errorMessage":"Missing {SEC_WEBSOCKET_PROTOCOL} header","messagePattern":"Missing (.+?) header","errorType":"http","errorClass":"WebSocketError","httpStatus":400,"severity":"error","filePath":"v3/crates/graphql/graphql-ws/src/websocket/mod.rs","lineNumber":114,"sourceCode":"                        });\n                    // Set the WebSocket id response header\n                    response\n                        .headers_mut()\n                        .insert(SEC_WEBSOCKET_ID, websocket_id.to_string().parse()?);\n                    Ok(response)\n                })\n            },\n        );\n\n        result.unwrap_or_else(IntoResponse::into_response)\n    }\n}\n\n/// Error types for WebSocket connections.\n#[derive(Debug, thiserror::Error)]\npub enum WebSocketError {\n    /// Error when the Sec-WebSocket-Protocol header is missing\n    #[error(\"Missing {SEC_WEBSOCKET_PROTOCOL} header\")]\n    MissingProtocolHeader,\n\n    /// Error when the header value cannot be converted to a string\n    #[error(\"{SEC_WEBSOCKET_PROTOCOL} header: {0}\")]\n    InvalidHeaderValue(#[from] ToStrError),\n\n    /// Error when the GraphQL WebSocket protocol is not included\n    #[error(\"Expecting {} protocol\", protocol::GRAPHQL_WS_PROTOCOL)]\n    ExpectingGraphqlWsProtocol,\n\n    /// Error when setting the WebSocket ID header value fails in response\n    #[error(\"Unable to set {SEC_WEBSOCKET_ID} header value: {0}\")]\n    WebSocketIdInvalidHeaderValue(#[from] InvalidHeaderValue),\n}\n\nimpl tracing_util::TraceableError for WebSocketError {\n    fn visibility(&self) -> tracing_util::ErrorVisibility {\n        match self {","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/hasura/graphql-engine/blob/724551b9ae87845594ef0408cff0e50eb6c90dc5/v3/crates/graphql/graphql-ws/src/websocket/mod.rs#L96-L132","documentation":"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`.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nconst ws = new WebSocket('wss://api.example.com/graphql');\n// after\nconst ws = new WebSocket('wss://api.example.com/graphql','graphql-transport-ws');","handlingStrategy":"validation","validationCode":"const ws = new WebSocket(url, 'graphql-transport-ws'); // always pass the protocol","typeGuard":null,"tryCatchPattern":"catch (e) { if (String(e).includes('Missing') && String(e).includes('header')) { reconnect with subprotocol; } }","preventionTips":["Always specify the subprotocol in the WebSocket constructor","Configure proxies to forward Sec-WebSocket-Protocol","Smoke-test the handshake in CI"],"tags":["websocket","graphql-ws","subprotocol","handshake"],"backgroundTag":"missing-websocket-subprotocol","analyzedSha":"724551b9ae87845594ef0408cff0e50eb6c90dc5","analyzedAt":"2026-08-28T07:32:55.105Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}