{"record":{"id":"baf4d9226af48f2d","repo":"hasura/graphql-engine","slug":"unable-to-fetch-message-from-websocket-0","errorCode":null,"errorMessage":"Unable to fetch message from WebSocket: {0}","messagePattern":"Unable to fetch message from WebSocket: (.+?)","errorType":"exception","errorClass":"ParseError","httpStatus":null,"severity":"error","filePath":"v3/crates/graphql/graphql-ws/src/websocket/tasks.rs","lineNumber":164,"sourceCode":"                    })\n                },\n            )\n            .await\n            .into_inner();\n        if break_loop == BreakLoop::Break {\n            break;\n        }\n    }\n}\n\nenum ParsedClientMessage {\n    Close,\n    Protocol(protocol::types::ClientMessage),\n}\n\n#[derive(thiserror::Error, Debug)]\nenum ParseError {\n    #[error(\"Unable to fetch message from WebSocket: {0}\")]\n    WebSocket(#[from] axum::Error),\n    #[error(\"Unable to parse WebSocket message: {0}\")]\n    Json(#[from] serde_json::Error),\n}\n\nimpl tracing_util::TraceableError for ParseError {\n    fn visibility(&self) -> tracing_util::ErrorVisibility {\n        tracing_util::ErrorVisibility::User\n    }\n}\n\nfn parse_incoming_message(\n    message: Result<ws::Message, axum::Error>,\n) -> Result<ParsedClientMessage, ParseError> {\n    let tracer = tracing_util::global_tracer();\n    tracer.in_span(\n        \"parse_incoming_message\",\n        \"Parse WebSocket message frame\",","sourceCodeStart":146,"sourceCodeEnd":182,"githubUrl":"https://github.com/hasura/graphql-engine/blob/724551b9ae87845594ef0408cff0e50eb6c90dc5/v3/crates/graphql/graphql-ws/src/websocket/tasks.rs#L146-L182","documentation":"This variant of ParseError wraps an axum::Error raised while reading the next message from the underlying WebSocket stream in the graphql-ws message pump task. It indicates a transport-level failure (socket closed, protocol violation, IO error) rather than a GraphQL-level problem. The message pump surfaces it so the connection can be torn down and traced.","triggerScenarios":"The peer abruptly closes or resets the TCP connection, the socket enters an invalid WebSocket frame state, or an IO error occurs while the server awaits the next message via the axum WebSocket stream API.","commonSituations":"Clients dropping connections (mobile networks, page reloads, load balancer idle timeouts killing sockets), malformed WebSocket frames from non-conformant clients, proxies interrupting the stream.","solutions":["Check server logs for the underlying axum error cause to identify whether it's a clean close vs an IO failure","Verify network stability and proxy/load-balancer idle timeout settings for WebSocket connections","Ensure the client uses a standards-compliant WebSocket implementation and handles reconnects (graphql-ws retry semantics)"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// On the client: treat socket errors as transient and reconnect with backoff\nclient.dispose();\nsetTimeout(() => reconnect(), backoffMs());","preventionTips":["Enable keep-alive/ping frames so intermediaries don't drop idle sockets","Raise load-balancer idle timeouts for WebSocket routes","Use a client with built-in reconnect (graphql-ws retry) for transient transport failures"],"tags":["websocket","transport","axum","io","rust"],"backgroundTag":"websocket-read-failure","analyzedSha":"724551b9ae87845594ef0408cff0e50eb6c90dc5","analyzedAt":"2026-08-28T07:32:55.105Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}