{"record":{"id":"eadf841292b55ed0","repo":"discordjs/discord.js","slug":"tried-to-connect-a-shard-that-wasn-t-idle","errorCode":null,"errorMessage":"Tried to connect a shard that wasn't idle","messagePattern":"Tried to connect a shard that wasn't idle","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/ws/src/ws/WebSocketShard.ts","lineNumber":183,"sourceCode":"\t\t\t\tonce(this, WebSocketShardEvents.Resumed, { signal: controller.signal }),\n\t\t\t]);\n\t\t}\n\n\t\tvoid this.internalConnect();\n\n\t\ttry {\n\t\t\tawait promise;\n\t\t} finally {\n\t\t\t// cleanup hanging listeners\n\t\t\tcontroller.abort();\n\t\t}\n\n\t\tthis.initialConnectResolved = true;\n\t}\n\n\tprivate async internalConnect() {\n\t\tif (this.#status !== WebSocketShardStatus.Idle) {\n\t\t\tthrow new Error(\"Tried to connect a shard that wasn't idle\");\n\t\t}\n\n\t\tconst { version, encoding, compression, useIdentifyCompression } = this.strategy.options;\n\t\tthis.identifyCompressionEnabled = useIdentifyCompression;\n\n\t\tconst params = new URLSearchParams({ v: version, encoding });\n\t\tif (compression !== null) {\n\t\t\tif (useIdentifyCompression) {\n\t\t\t\tconsole.warn('WebSocketShard: transport compression is enabled, disabling identify compression');\n\t\t\t\tthis.identifyCompressionEnabled = false;\n\t\t\t}\n\n\t\t\tparams.append('compress', CompressionParameterMap[compression]);\n\n\t\t\tswitch (compression) {\n\t\t\t\tcase CompressionMethod.ZlibNative: {\n\t\t\t\t\tconst zlib = await getNativeZlib();\n\t\t\t\t\tif (zlib) {","sourceCodeStart":165,"sourceCodeEnd":201,"githubUrl":"https://github.com/discordjs/discord.js/blob/a81ed8a306d37fdc746e26a634b6a42164ba2c8c/packages/ws/src/ws/WebSocketShard.ts#L165-L201","documentation":"WebSocketShard.internalConnect() only makes sense from the Idle status. If the shard is already Connecting/Connected (or in another non-idle state) it throws to prevent a second WebSocket connection / identify for the same shard.","triggerScenarios":"Calling shard.connect() (or manager.connect() re-invoked) while the shard is already connecting or connected; internalConnect also being reachable via destroy() paths when the shard's status is not Idle.","commonSituations":"Calling connect() twice due to duplicate startup code or double event registration; race between an automatic resume/reconnect and a manual connect(); awaiting missing on an async connect call.","solutions":["Ensure connect() is awaited and called only once per shard lifecycle","Check shard.status === WebSocketShardStatus.Idle before calling connect()","Don't manually connect a shard that the manager's strategy already manages — use manager.connect()","On 'not idle' errors, inspect the status to decide whether to destroy({recover:true}) instead of connecting"],"exampleFix":"// before\nawait shard.connect();\n// after\nif (shard.status === WebSocketShardStatus.Idle) {\n  await shard.connect();\n}","handlingStrategy":"validation","validationCode":"if (shard.status !== WebSocketShardStatus.Idle) {\n  return; // already connecting/connected\n}\nawait shard.connect();","typeGuard":"function canConnect(shard: WebSocketShard): boolean {\n  return shard.status === WebSocketShardStatus.Idle;\n}","tryCatchPattern":"try {\n  await shard.connect();\n} catch (e) {\n  if (e instanceof Error && e.message.includes(\"wasn't idle\")) {\n    // already connecting — nothing to do\n  } else throw e;\n}","preventionTips":["Call connect() only once per shard and always await it","Prefer manager.connect() over direct shard.connect() in application code","Serialize startup logic so reconnect logic and manual connects don't overlap"],"tags":["websocket","lifecycle","state"],"backgroundTag":"invalid-state-transition","analyzedSha":"a81ed8a306d37fdc746e26a634b6a42164ba2c8c","analyzedAt":"2026-08-30T04:07:22.193Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}