websockets/ws · error · Error

WebSocket is not open: readyState 0 (CONNECTING)

Error message

WebSocket is not open: readyState 0 (CONNECTING)

What it means

Thrown by WebSocket.prototype.ping() at websocket.js:368-369 when readyState is CONNECTING (0), i.e. the opening handshake has not completed. Unlike the CLOSING/CLOSED case (which routes to sendAfterClose), CONNECTING is treated as a hard error because the sender is not yet attached to a socket. The guard throws synchronously before any argument reshuffling.

Solutions

  1. Wait for the 'open' event before pinging: ws.on('open', () => ws.ping()).
  2. Guard every call: if (ws.readyState === WebSocket.OPEN) ws.ping().
  3. Move heartbeat logic into an interval started in the 'open' handler and cleared on 'close'.

Example fix

// before
const ws = new WebSocket(url);
ws.ping(); // throws: still CONNECTING

// after
const ws = new WebSocket(url);
ws.on('open', () => ws.ping());
Defensive patterns

Strategy: validation

Validate before calling

function safePing(ws, data) {
  if (ws.readyState !== ws.OPEN) return false;
  ws.ping(data);
  return true;
}

Type guard

function isOpen(ws) {
  return ws.readyState === WebSocket.OPEN; // 1
}

Try / catch

try {
  ws.ping(data);
} catch (err) {
  if (/CONNECTING/.test(err.message)) {
    // defer until open
    ws.once('open', () => ws.ping(data));
  } else throw err;
}

Prevention

When it happens

Trigger: Calling ws.ping(...) immediately after `new WebSocket(url)` before the 'open' event fires; calling ping inside a 'connecting' or constructor-adjacent code path; calling ping from an 'upgrade' event listener (which fires before 'open'). The check at line 368 catches readyState === 0 and throws.

Common situations: Sending a keepalive/heartbeat ping in a function that runs before the connection opens (e.g. right after construction, or in a retry loop); a reconnection manager that pings before re-handshake completes; unit tests that construct a WebSocket and immediately ping without waiting.

Related errors


AI-assisted analysis of websockets/ws@c791e707ea (2026-08-06). Data as JSON: /api/errors/85adf974922b5521. Report an issue: GitHub.

Appendix: source

Thrown at lib/websocket.js:369

    ) {
      return;
    }

    this._paused = true;
    this._socket.pause();
  }

  /**
   * Send a ping.
   *
   * @param {*} [data] The data to send
   * @param {Boolean} [mask] Indicates whether or not to mask `data`
   * @param {Function} [cb] Callback which is executed when the ping is sent
   * @public
   */
  ping(data, mask, cb) {
    if (this.readyState === WebSocket.CONNECTING) {
      throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');
    }

    if (typeof data === 'function') {
      cb = data;
      data = mask = undefined;
    } else if (typeof mask === 'function') {
      cb = mask;
      mask = undefined;
    }

    if (typeof data === 'number') data = data.toString();

    if (this.readyState !== WebSocket.OPEN) {
      sendAfterClose(this, data, cb);
      return;
    }

    if (mask === undefined) mask = !this._isServer;

View on GitHub (pinned to c791e707ea)