{"record":{"id":"4a06e191de3f5bd8","repo":"discordjs/discord.js","slug":"websocketshard-wasn-t-connected","errorCode":null,"errorMessage":"WebSocketShard wasn't connected","messagePattern":"WebSocketShard wasn't connected","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/ws/src/ws/WebSocketShard.ts","lineNumber":457,"sourceCode":"\n\t\t\treturn { ok: false };\n\t\t} finally {\n\t\t\tif (timeout) {\n\t\t\t\tclearTimeout(timeout);\n\t\t\t}\n\n\t\t\tthis.timeoutAbortControllers.delete(event);\n\n\t\t\t// Clean up the close listener to not leak memory\n\t\t\tif (!closeController.signal.aborted) {\n\t\t\t\tcloseController.abort();\n\t\t\t}\n\t\t}\n\t}\n\n\tpublic async send(payload: GatewaySendPayload): Promise<void> {\n\t\tif (!this.connection) {\n\t\t\tthrow new Error(\"WebSocketShard wasn't connected\");\n\t\t}\n\n\t\t// Generally, the way we treat payloads is 115/60 seconds. The actual limit is 120/60, so we have a bit of leeway.\n\t\t// We use that leeway for those special payloads that we just fire with no checking, since there's no shot we ever\n\t\t// send more than 5 of those in a 60 second interval. This way we can avoid more complex queueing logic.\n\n\t\tif (ImportantGatewayOpcodes.has(payload.op)) {\n\t\t\tthis.connection.send(JSON.stringify(payload));\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.#status !== WebSocketShardStatus.Ready && !ImportantGatewayOpcodes.has(payload.op)) {\n\t\t\tthis.debug(['Tried to send a non-crucial payload before the shard was ready, waiting']);\n\t\t\t// This will throw if the shard throws an error event in the meantime, just requeue the payload\n\t\t\ttry {\n\t\t\t\tawait once(this, WebSocketShardEvents.Ready);\n\t\t\t} catch {\n\t\t\t\treturn this.send(payload);","sourceCodeStart":439,"sourceCodeEnd":475,"githubUrl":"https://github.com/discordjs/discord.js/blob/a81ed8a306d37fdc746e26a634b6a42164ba2c8c/packages/ws/src/ws/WebSocketShard.ts#L439-L475","documentation":"WebSocketShard.send() requires an open WebSocket connection. If this.connection is null (shard never connected, was closed, or is mid-reconnect), the payload cannot be delivered and it throws.","triggerScenarios":"Calling send() (directly or via identify/resume/heartbeat) while the shard is disconnected — before connect() completes, after a close event, or during a reconnect window.","commonSituations":"Sending presence updates or gateway commands from app code right after startup before READY; sending after the socket dropped and auto-reconnect hasn't finished; firing send from a timer that outlives the shard's lifetime after destroy().","solutions":["Wait for the shard's 'ready' event/status before sending payloads","Check that the connection exists / shard status before send, or wrap sends in try-catch and requeue","Stop send loops (intervals) on shard destroy/close events","Let the manager-level strategy handle reconnection before resuming sends"],"exampleFix":"// before\nshard.send({ op: GatewayOpcodes.PresenceUpdate, d: presence });\n// after\nif (shard.status === WebSocketShardStatus.Ready) {\n  shard.send({ op: GatewayOpcodes.PresenceUpdate, d: presence });\n} else {\n  pendingPayloads.push({ op: GatewayOpcodes.PresenceUpdate, d: presence });\n}","handlingStrategy":"validation","validationCode":"function canSend(shard: WebSocketShard): boolean {\n  return shard.status === WebSocketShardStatus.Ready;\n}\nif (canSend(shard)) shard.send(payload);","typeGuard":"function isConnected(shard: WebSocketShard): boolean {\n  return shard.status === WebSocketShardStatus.Ready;\n}","tryCatchPattern":"try {\n  await shard.send(payload);\n} catch (e) {\n  if (e instanceof Error && e.message.includes(\"wasn't connected\")) {\n    requeue.push(payload); // resend once shard is ready again\n  } else throw e;\n}","preventionTips":["Wait for the shard ready event before issuing gateway commands","Clear intervals/timers that send payloads when a shard is destroyed","Queue outbound payloads during reconnects instead of sending blindly"],"tags":["websocket","connection","lifecycle"],"backgroundTag":"websocket-not-connected","analyzedSha":"a81ed8a306d37fdc746e26a634b6a42164ba2c8c","analyzedAt":"2026-08-30T04:07:22.193Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}