{"record":{"id":"d810508ca1aa9c41","repo":"hasura/graphql-engine","slug":"connection-already-initialized","errorCode":null,"errorMessage":"Connection already initialized","messagePattern":"Connection already initialized","errorType":"exception","errorClass":"ConnectionInitError","httpStatus":null,"severity":"error","filePath":"v3/crates/graphql/graphql-ws/src/protocol/init.rs","lineNumber":120,"sourceCode":"                            .await?;\n                            // Authorize the authenticated identity\n                            let session = authorize_identity(&auth_response.identity, &headers)?;\n                            Ok((session, headers))\n                        }\n                        ConnectionInitState::Initialized { .. } => {\n                            Err(ConnectionInitError::AlreadyInitialized)\n                        }\n                    }\n                })\n            },\n        )\n        .await\n}\n\n/// Error types that may occur during connection initialization.\n#[derive(Debug, thiserror::Error)]\npub enum ConnectionInitError {\n    #[error(\"Connection already initialized\")]\n    AlreadyInitialized,\n    #[error(\"Invalid header name: {0}\")]\n    InvalidHeaderName(#[from] http::header::InvalidHeaderName),\n    #[error(\"Invalid header value: {0}\")]\n    InvalidHeaderValue(#[from] http::header::InvalidHeaderValue),\n    #[error(\"AuthError: {0}\")]\n    Authn(#[from] AuthError),\n    #[error(\"SessionError: {0}\")]\n    Session(#[from] SessionError),\n}\n\nimpl tracing_util::TraceableError for ConnectionInitError {\n    fn visibility(&self) -> tracing_util::ErrorVisibility {\n        tracing_util::ErrorVisibility::User\n    }\n}\n\n/// Parses headers from a given map of strings into an `http::HeaderMap`.","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/hasura/graphql-engine/blob/724551b9ae87845594ef0408cff0e50eb6c90dc5/v3/crates/graphql/graphql-ws/src/protocol/init.rs#L102-L138","documentation":"ConnectionInitError::AlreadyInitialized is returned by the graphql-ws protocol layer when a client attempts to perform connection initialization on a WebSocket connection that has already been initialized. The graphql-transport-ws protocol allows exactly one 'connection_init' message; a second one is a protocol violation and produces this error, typically closing the socket with 4408 'Connection initialisation timeout' semantics or a server close.","triggerScenarios":"A WebSocket client sends a second 'connection_init' message after the connection was already acknowledged with 'connection_ack', or re-runs an init handshake on an existing socket. Also occurs when buggy client logic re-initiates the handshake on reconnect without opening a new socket.","commonSituations":"Custom graphql-ws client implementations that send connection_init on every subscription instead of once per socket; reconnection logic that reuses the old socket object; race conditions where auth-refresh code re-sends init; proxy/sticky-session issues delivering one client's init to an already-initialized connection.","solutions":["Send 'connection_init' exactly once per WebSocket connection, immediately after the socket opens, and wait for 'connection_ack' before subscribing","On reconnect, always open a fresh WebSocket connection rather than reusing the old one","Use a maintained client library (graphql-ws npm package) instead of a hand-rolled protocol implementation","Add a client-side state flag (initialized=true after ack) to guard against duplicate init sends"],"exampleFix":"// before\nsocket.on('sub', () => socket.send(msg('connection_init', payload)));\n\n// after\nlet initialized = false;\nfunction ensureInit() {\n  if (!initialized) { socket.send(msg('connection_init', payload)); }\n}","handlingStrategy":"validation","validationCode":"// Client: track init state per socket before sending messages\nlet initialized = socket.waitForMessage('connection_ack') !== null;\nfunction send(msg) {\n  if (msg.type === 'connection_init' && initialized) {\n    throw new Error('connection already initialized; open a new socket');\n  }\n  socket.send(JSON.stringify(msg));\n}","typeGuard":null,"tryCatchPattern":"match ws_conn.initialize(payload).await {\n    Err(ConnectionInitError::AlreadyInitialized) => {\n        // protocol violation: close 4400-series and force the client to reconnect fresh\n        ws_conn.close(CloseCode::PolicyViolation, \"duplicate connection_init\").await;\n    }\n    Err(e) => log_init_error(e),\n    Ok(()) => (),\n}","preventionTips":["Send connection_init exactly once per socket and await connection_ack before subscriptions","On reconnect, create a new WebSocket rather than re-initializing the old one","Prefer the maintained graphql-ws client library over hand-rolled protocol code"],"tags":["rust","graphql","websocket","graphql-ws","protocol-violation"],"backgroundTag":"websocket-already-initialized","analyzedSha":"724551b9ae87845594ef0408cff0e50eb6c90dc5","analyzedAt":"2026-08-28T07:32:55.105Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}