{"record":{"id":"85adf974922b5521","repo":"websockets/ws","slug":"websocket-is-not-open-readystate-0-connecting","errorCode":null,"errorMessage":"WebSocket is not open: readyState 0 (CONNECTING)","messagePattern":"WebSocket is not open: readyState 0 \\(CONNECTING\\)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/websocket.js","lineNumber":369,"sourceCode":"    ) {\n      return;\n    }\n\n    this._paused = true;\n    this._socket.pause();\n  }\n\n  /**\n   * Send a ping.\n   *\n   * @param {*} [data] The data to send\n   * @param {Boolean} [mask] Indicates whether or not to mask `data`\n   * @param {Function} [cb] Callback which is executed when the ping is sent\n   * @public\n   */\n  ping(data, mask, cb) {\n    if (this.readyState === WebSocket.CONNECTING) {\n      throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');\n    }\n\n    if (typeof data === 'function') {\n      cb = data;\n      data = mask = undefined;\n    } else if (typeof mask === 'function') {\n      cb = mask;\n      mask = undefined;\n    }\n\n    if (typeof data === 'number') data = data.toString();\n\n    if (this.readyState !== WebSocket.OPEN) {\n      sendAfterClose(this, data, cb);\n      return;\n    }\n\n    if (mask === undefined) mask = !this._isServer;","sourceCodeStart":351,"sourceCodeEnd":387,"githubUrl":"https://github.com/websockets/ws/blob/c791e707eab3c13dd9a261d2479c3cc4a49a6fed/lib/websocket.js#L351-L387","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Wait for the 'open' event before pinging: ws.on('open', () => ws.ping()).","Guard every call: if (ws.readyState === WebSocket.OPEN) ws.ping().","Move heartbeat logic into an interval started in the 'open' handler and cleared on 'close'."],"exampleFix":"// before\nconst ws = new WebSocket(url);\nws.ping(); // throws: still CONNECTING\n\n// after\nconst ws = new WebSocket(url);\nws.on('open', () => ws.ping());","handlingStrategy":"validation","validationCode":"function safePing(ws, data) {\n  if (ws.readyState !== ws.OPEN) return false;\n  ws.ping(data);\n  return true;\n}","typeGuard":"function isOpen(ws) {\n  return ws.readyState === WebSocket.OPEN; // 1\n}","tryCatchPattern":"try {\n  ws.ping(data);\n} catch (err) {\n  if (/CONNECTING/.test(err.message)) {\n    // defer until open\n    ws.once('open', () => ws.ping(data));\n  } else throw err;\n}","preventionTips":["Start heartbeat intervals inside the 'open' handler, not after construction.","Guard all ping calls with ws.readyState === WebSocket.OPEN.","Clear heartbeat timers on 'close'/'error'."],"tags":["websocket","ping","readystate","connecting","lifecycle"],"backgroundTag":null,"analyzedSha":"c791e707eab3c13dd9a261d2479c3cc4a49a6fed","analyzedAt":"2026-08-06T19:07:51.047Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}