{"id":"7a13157ac0069a3d","repo":"websockets/ws","slug":"server-handleupgrade-was-called-more-than-once-w","errorCode":null,"errorMessage":"server.handleUpgrade() was called more than once with the same socket, possibly due to a misconfiguration","messagePattern":"server\\.handleUpgrade\\(\\) was called more than once with the same socket, possibly due to a misconfiguration","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"lib/websocket-server.js","lineNumber":379,"sourceCode":"   *\n   * @param {Object} extensions The accepted extensions\n   * @param {String} key The value of the `Sec-WebSocket-Key` header\n   * @param {Set} protocols The subprotocols\n   * @param {http.IncomingMessage} req The request object\n   * @param {Duplex} socket The network socket between the server and client\n   * @param {Buffer} head The first packet of the upgraded stream\n   * @param {Function} cb Callback\n   * @throws {Error} If called more than once with the same socket\n   * @private\n   */\n  completeUpgrade(extensions, key, protocols, req, socket, head, cb) {\n    //\n    // Destroy the socket if the client has already sent a FIN packet.\n    //\n    if (!socket.readable || !socket.writable) return socket.destroy();\n\n    if (socket[kWebSocket]) {\n      throw new Error(\n        'server.handleUpgrade() was called more than once with the same ' +\n          'socket, possibly due to a misconfiguration'\n      );\n    }\n\n    if (this._state > RUNNING) return abortHandshake(socket, 503);\n\n    const digest = createHash('sha1')\n      .update(key + GUID)\n      .digest('base64');\n\n    const headers = [\n      'HTTP/1.1 101 Switching Protocols',\n      'Upgrade: websocket',\n      'Connection: Upgrade',\n      `Sec-WebSocket-Accept: ${digest}`\n    ];\n","sourceCodeStart":361,"sourceCodeEnd":397,"githubUrl":"https://github.com/websockets/ws/blob/ae1de54330cef77e487548890fabfeb9aae1d83d/lib/websocket-server.js#L361-L397","documentation":"Thrown by WebSocketServer.completeUpgrade() (lib/websocket-server.js:378-383) when the same network socket has already been upgraded and tagged via socket[kWebSocket]. This happens when handleUpgrade() is invoked more than once for a single TCP socket, which the library treats as a misconfiguration because a socket can only back one WebSocket connection. It is a synchronous throw from within handleUpgrade() and will crash the process if uncaught.","triggerScenarios":"Attaching two or more WebSocketServer instances to the same HTTP server's 'upgrade' event and both calling handleUpgrade on the same req/socket; calling wss.handleUpgrade() manually in a loop or in overlapping branches of an if/else; a single server with both { server } mode and a manual 'upgrade' handler that both forward to handleUpgrade.","commonSituations":"Running multiple WebSocket endpoints on one HTTP server without using the path option or shouldHandle to discriminate; copy-pasting the noServer example twice; middleware that re-emits 'upgrade' events; upgrading from one WSS to two without splitting upgrade handling.","solutions":["Ensure each 'upgrade' event is handled by exactly one WebSocketServer: use the path option or a custom shouldHandle/verifyClient to route.","If you need two servers on one HTTP server, branch in your single 'upgrade' listener and call handleUpgrade on only one of them.","Avoid registering multiple 'upgrade' listeners that all call handleUpgrade unconditionally."],"exampleFix":"// before\nhttpServer.on('upgrade', (req, socket, head) => {\n  wss1.handleUpgrade(req, socket, head, () => {});\n  wss2.handleUpgrade(req, socket, head, () => {}); // double upgrade!\n});\n\n// after\nhttpServer.on('upgrade', (req, socket, head) => {\n  const { pathname } = new URL(req.url, 'http://x');\n  if (pathname === '/a') wss1.handleUpgrade(req, socket, head, () => {});\n  else wss2.handleUpgrade(req, socket, head, () => {});\n});","handlingStrategy":"validation","validationCode":"httpServer.on('upgrade', (req, socket, head) => {\n  if (socket[kWebSocket]) return; // already upgraded, ignore\n  const { pathname } = new URL(req.url, 'http://x');\n  const target = pathname === '/a' ? wss1 : wss2;\n  target.handleUpgrade(req, socket, head, (ws) => {/* ... */});\n});","typeGuard":"const { kWebSocket } = require('ws/lib/constants');\nfunction isSocketUpgradeable(socket) {\n  return !socket[kWebSocket];\n}","tryCatchPattern":"try {\n  wss.handleUpgrade(req, socket, head, cb);\n} catch (err) {\n  if (/more than once with the same socket/.test(err.message)) {\n    // double upgrade: ensure only one WSS handles this socket\n    socket.destroy();\n  } else {\n    throw err;\n  }\n}","preventionTips":["Route each 'upgrade' event to exactly one WebSocketServer via path or shouldHandle.","Never register multiple 'upgrade' listeners that all call handleUpgrade unconditionally.","If using a single HTTP server with two endpoints, branch in one listener and pick the target."],"tags":["websocket-server","handle-upgrade","configuration","crash"],"analyzedSha":"ae1de54330cef77e487548890fabfeb9aae1d83d","analyzedAt":"2026-08-03T19:11:18.437Z","schemaVersion":2}