hasura/graphql-engine · error · ConnectionTimeOutError

Connection initialization timed out

Error message

Connection initialization timed out

What it means

The graphql-ws server starts a timer when a WebSocket connection is opened and expects the client to send the ConnectionInit message within the configured connection initialization window. If no init message arrives in time, the server gives up and reports this timeout error and closes the socket. This protects the server from idle or half-open connections occupying resources.

Source

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

use super::types;
use crate::metrics::WebSocketMetrics;
use crate::protocol;
use axum::extract::ws;
use futures_util::{SinkExt, StreamExt};
use tokio::time::{Duration, timeout};

/// Enum to represent whether the loop should continue or break.
#[derive(PartialEq)]
enum BreakLoop {
    /// Indicates the loop should break.
    Break,
    /// Indicates the loop should continue.
    Dont,
}

/// Error type for connection timeouts during WebSocket initialization.
#[derive(thiserror::Error, Debug)]
#[error("Connection initialization timed out")]
pub(crate) struct ConnectionTimeOutError;

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

/// Checks if the graphql-ws protocol is initialized within the specified timeout duration.
/// Ref: <https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md#connectioninit>
pub(crate) async fn verify_connection_init<M: Send>(
    connection: types::Connection<M>,
    timeout_duration: Duration,
    parent_span_link: tracing_util::SpanLink,
) -> Result<(), ConnectionTimeOutError> {
    let tracer = tracing_util::global_tracer();
    tracer
        .new_trace_async_with_link(

View on GitHub (pinned to 724551b9ae)

Solutions

  1. Ensure your client sends connection_init immediately after the socket opens (graphql-ws clients do this automatically when a payload/callback is provided)
  2. Increase the server's connection init timeout configuration if clients are slow to initialize
  3. Check for intermediaries that delay or buffer the first WebSocket frame

Example fix

// before (client)
const ws = new WebSocket(url, 'graphql-ws');
// ...subscribe without initializing

// after
import { createClient } from 'graphql-ws';
const client = createClient({ webSocketImpl: ws, connectionInit: { authorization: token } });
Defensive patterns

Strategy: retry

Validate before calling

// Ensure connectionInit is provided so the client sends connection_init immediately
const client = createClient({ webSocketImpl: ws, connectionInit: {{}} });

Prevention

When it happens

Trigger: A client opens the WebSocket but never sends the 'connection_init' message (no payload or a client bug), or network/latency causes it to arrive after the configured connection_init_timeout window elapses.

Common situations: Custom WebSocket clients that only subscribe without initializing; heavy startup work on the client delaying the init frame; misconfigured very short connection init timeout on the server; NAT/proxy idle handling delaying the first frame.

Understand the failure class

Related errors


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