hasura/graphql-engine · error · ParseError

Unable to fetch message from WebSocket: {0}

Error message

Unable to fetch message from WebSocket: {0}

What it means

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.

Source

Thrown at v3/crates/graphql/graphql-ws/src/websocket/tasks.rs:164

                    })
                },
            )
            .await
            .into_inner();
        if break_loop == BreakLoop::Break {
            break;
        }
    }
}

enum ParsedClientMessage {
    Close,
    Protocol(protocol::types::ClientMessage),
}

#[derive(thiserror::Error, Debug)]
enum ParseError {
    #[error("Unable to fetch message from WebSocket: {0}")]
    WebSocket(#[from] axum::Error),
    #[error("Unable to parse WebSocket message: {0}")]
    Json(#[from] serde_json::Error),
}

impl tracing_util::TraceableError for ParseError {
    fn visibility(&self) -> tracing_util::ErrorVisibility {
        tracing_util::ErrorVisibility::User
    }
}

fn parse_incoming_message(
    message: Result<ws::Message, axum::Error>,
) -> Result<ParsedClientMessage, ParseError> {
    let tracer = tracing_util::global_tracer();
    tracer.in_span(
        "parse_incoming_message",
        "Parse WebSocket message frame",

View on GitHub (pinned to 724551b9ae)

Solutions

  1. Check server logs for the underlying axum error cause to identify whether it's a clean close vs an IO failure
  2. Verify network stability and proxy/load-balancer idle timeout settings for WebSocket connections
  3. Ensure the client uses a standards-compliant WebSocket implementation and handles reconnects (graphql-ws retry semantics)
Defensive patterns

Strategy: retry

Try / catch

// On the client: treat socket errors as transient and reconnect with backoff
client.dispose();
setTimeout(() => reconnect(), backoffMs());

Prevention

When it happens

Trigger: 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.

Common situations: Clients dropping connections (mobile networks, page reloads, load balancer idle timeouts killing sockets), malformed WebSocket frames from non-conformant clients, proxies interrupting the stream.

Related errors


AI-assisted analysis of hasura/graphql-engine@724551b9ae (2026-08-28). Data as JSON: /api/errors/baf4d9226af48f2d. Report an issue: GitHub.