discordjs/discord.js · error · Error
Tried to connect a shard that wasn't idle
Error message
Tried to connect a shard that wasn't idle
What it means
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.
Source
Thrown at packages/ws/src/ws/WebSocketShard.ts:183
once(this, WebSocketShardEvents.Resumed, { signal: controller.signal }),
]);
}
void this.internalConnect();
try {
await promise;
} finally {
// cleanup hanging listeners
controller.abort();
}
this.initialConnectResolved = true;
}
private async internalConnect() {
if (this.#status !== WebSocketShardStatus.Idle) {
throw new Error("Tried to connect a shard that wasn't idle");
}
const { version, encoding, compression, useIdentifyCompression } = this.strategy.options;
this.identifyCompressionEnabled = useIdentifyCompression;
const params = new URLSearchParams({ v: version, encoding });
if (compression !== null) {
if (useIdentifyCompression) {
console.warn('WebSocketShard: transport compression is enabled, disabling identify compression');
this.identifyCompressionEnabled = false;
}
params.append('compress', CompressionParameterMap[compression]);
switch (compression) {
case CompressionMethod.ZlibNative: {
const zlib = await getNativeZlib();
if (zlib) {View on GitHub (pinned to a81ed8a306)
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
Example fix
// before
await shard.connect();
// after
if (shard.status === WebSocketShardStatus.Idle) {
await shard.connect();
} Defensive patterns
Strategy: validation
Validate before calling
if (shard.status !== WebSocketShardStatus.Idle) {
return; // already connecting/connected
}
await shard.connect(); Type guard
function canConnect(shard: WebSocketShard): boolean {
return shard.status === WebSocketShardStatus.Idle;
} Try / catch
try {
await shard.connect();
} catch (e) {
if (e instanceof Error && e.message.includes("wasn't idle")) {
// already connecting — nothing to do
} else throw e;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- WebSocketShard wasn't connected
- ClientNotReady
- InteractionAlreadyReplied
- InteractionNotReplied
- Cannot destroy VoiceConnection - it has already been destroy
AI-assisted analysis of discordjs/discord.js@a81ed8a306 (2026-08-30).
Data as JSON: /api/errors/eadf841292b55ed0.
Report an issue: GitHub.