{"record":{"id":"f265c80556e17aa2","repo":"hasura/graphql-engine","slug":"graphql-ws-protocol-is-not-initialized","errorCode":null,"errorMessage":"graphql-ws protocol is not initialized","messagePattern":"graphql-ws protocol is not initialized","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/crates/graphql/graphql-ws/src/protocol/subscribe.rs","lineNumber":19,"sourceCode":"use super::types::{ConnectionInitState, OperationId, ServerMessage};\nuse crate::metrics::WebSocketMetrics;\nuse crate::poller;\nuse crate::websocket::types as ws;\nuse ::pre_response_plugin::execute::PreResponsePluginResponse;\nuse axum::http;\nuse blake2::{Blake2b, Digest};\nuse engine_types::ExposeInternalErrors;\nuse graphql_frontend::{ExecuteQueryResult, RootFieldResult, process_response};\nuse graphql_ir::RequestPlan;\nuse hasura_authn_core::Session;\nuse indexmap::IndexMap;\nuse nonempty::NonEmpty;\nuse pre_parse_plugin::execute as pre_parse_plugin;\nuse pre_response_plugin::execute as pre_response_plugin;\n\n#[derive(thiserror::Error, Debug)]\nenum Error {\n    #[error(\"graphql-ws protocol is not initialized\")]\n    NotInitialized,\n    #[error(\"poller with operation_id {} already exists\", operation_id.0)]\n    PollerAlreadyExists { operation_id: OperationId },\n    #[error(\"error in pre-parse plugin: {0}\")]\n    PreParsePlugin(#[from] pre_parse_plugin::Error),\n}\n\nimpl tracing_util::TraceableError for Error {\n    fn visibility(&self) -> tracing_util::ErrorVisibility {\n        tracing_util::ErrorVisibility::User\n    }\n}\n\n/// Handles the subscription message from the client.\n/// It either starts a new poller or sends a close message if the poller with given operation_id already exists.\npub async fn handle_subscribe<M: WebSocketMetrics>(\n    client_address: std::net::SocketAddr,\n    connection: ws::Connection<M>,","sourceCodeStart":1,"sourceCodeEnd":37,"githubUrl":"https://github.com/hasura/graphql-engine/blob/724551b9ae87845594ef0408cff0e50eb6c90dc5/v3/crates/graphql/graphql-ws/src/protocol/subscribe.rs#L1-L37","documentation":"Thrown by the graphql-ws subscribe handler when a `subscribe` message arrives before the protocol has been initialized via `connection_init`. The protocol state machine requires a successful initialization before any subscriptions can be created.","triggerScenarios":"Sending a `subscribe` message on a WebSocket before sending (or before the server has acknowledged) a `connection_init` message; also when initialization failed silently and the client proceeds to subscribe.","commonSituations":"Client library that skips connection_init; race where the client sends subscribe before processing the connection_ack; reconnect logic that reuses stale state and skips re-initialization.","solutions":["Ensure the client sends `connection_init` first and waits for `connection_ack` before subscribing","If reconnecting, re-run the full handshake instead of reusing the old socket state","Check that connection_init did not fail (auth errors often cause silent non-initialization)","Add client-side state tracking so subscribe is only called after ack"],"exampleFix":"// before\nws.onopen = () => ws.send(JSON.stringify({type:'subscribe',...}));\n// after\nlet ready = false;\nws.onopen = () => ws.send(JSON.stringify({type:'connection_init',payload:{...}}));\nws.onmessage = (m) => { if (JSON.parse(m.data).type==='connection_ack') ready = true; };\nws.sendSubscribe = () => { if (ready) ws.send(JSON.stringify({type:'subscribe',...})); };","handlingStrategy":"validation","validationCode":"let initialized = false;\nfunction assertInitialized(){ if(!initialized) throw new Error('connection not initialized'); }","typeGuard":null,"tryCatchPattern":"catch (e) { if (String(e).includes('not initialized')) { sendInit(); /* wait ack then resubscribe */ } }","preventionTips":["Always wait for connection_ack before subscribing","Re-run the handshake after any reconnect","Treat subscribe-before-ack as a client bug and fix state ordering"],"tags":["graphql-ws","websocket","protocol-state","subscriptions"],"backgroundTag":"websocket-handshake-order","analyzedSha":"724551b9ae87845594ef0408cff0e50eb6c90dc5","analyzedAt":"2026-08-28T07:32:55.105Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}