Skip to content
Latchkey

SignalR "WebSocket closed with status code: 1006" in CI

Close code 1006 is an abnormal closure: the connection dropped without a proper close frame. SignalR surfaces it as "WebSocket closed with status code: 1006" when the transport dies mid-stream.

What this error means

The connection's onclose fires (or start() rejects) with "Error: WebSocket closed with status code: 1006 ()". It appears when the server restarts, a proxy times out an idle socket, or the connection is reset.

SignalR
Error: WebSocket closed with status code: 1006 ().
    at WebSocketTransport._webSocket.onclose (node_modules/@microsoft/signalr/dist/cjs/WebSocketTransport.js:...)

Common causes

The connection was reset with no close handshake

A server restart, a crash, or a network reset tears down the socket without a close frame, which the client reports as 1006.

An idle-timeout proxy dropped the socket

A reverse proxy that closes idle upgraded connections kills a quiet SignalR socket, producing an abnormal 1006 close.

How to fix it

Enable automatic reconnect and keep-alive

  1. Configure withAutomaticReconnect() so a transient 1006 recovers.
  2. Keep the connection active or tune keep-alive so idle proxies do not cut it.
  3. Assert on the reconnected state rather than the first socket only.
test.mjs
const connection = new signalR.HubConnectionBuilder()
  .withUrl('http://localhost:5000/hub')
  .withAutomaticReconnect()
  .build();

Raise idle timeouts on the proxy

If a proxy fronts the hub, raise its read/idle timeout so quiet WebSocket connections are not closed as idle.

nginx.conf
proxy_read_timeout 300s;
proxy_send_timeout 300s;

How to prevent it

  • Use withAutomaticReconnect so a transient drop does not fail the test.
  • Keep upgraded connections alive under any idle-closing proxy.
  • Do not restart the hub while a client connection is open.

Related guides

Tired of flaky CI? Latchkey auto-heals failed jobs and retries them for you. Start free →