discordjs/discord.js · error · Error
Cannot destroy VoiceConnection - it has already been destroy
Error message
Cannot destroy VoiceConnection - it has already been destroyed
What it means
VoiceConnection.destroy() transitions the connection to the Destroyed state and releases resources; calling it on an already-destroyed connection throws this Error, since a second teardown is invalid.
Source
Thrown at packages/voice/src/VoiceConnection.ts:586
* @param buffer - The Opus packet to play
*/
public playOpusPacket(buffer: Buffer) {
const state = this.state;
if (state.status !== VoiceConnectionStatus.Ready) return;
state.networking.prepareAudioPacket(buffer);
return state.networking.dispatchAudio();
}
/**
* Destroys the VoiceConnection, preventing it from connecting to voice again.
* This method should be called when you no longer require the VoiceConnection to
* prevent memory leaks.
*
* @param adapterAvailable - Whether the adapter can be used
*/
public destroy(adapterAvailable = true) {
if (this.state.status === VoiceConnectionStatus.Destroyed) {
throw new Error('Cannot destroy VoiceConnection - it has already been destroyed');
}
if (getVoiceConnection(this.joinConfig.guildId, this.joinConfig.group) === this) {
untrackVoiceConnection(this);
}
if (adapterAvailable) {
this.state.adapter.sendPayload(createJoinVoiceChannelPayload({ ...this.joinConfig, channelId: null }));
}
this.state = {
status: VoiceConnectionStatus.Destroyed,
};
}
/**
* Disconnects the VoiceConnection, allowing the possibility of rejoining later on.
*View on GitHub (pinned to a81ed8a306)
Solutions
- Check connection.state.status !== VoiceConnectionStatus.Destroyed before calling destroy()
- Track destruction with a boolean or set so cleanup runs at most once
- Wrap destroy() in try/catch in generic cleanup code
Example fix
// before
connection.destroy();
// after
if (connection.state.status !== VoiceConnectionStatus.Destroyed) {
connection.destroy();
} Defensive patterns
Strategy: validation
Validate before calling
import { VoiceConnectionStatus } from '@discordjs/voice';
if (connection.state.status !== VoiceConnectionStatus.Destroyed) {
connection.destroy();
} Try / catch
try {
connection.destroy();
} catch (err) {
if (err.message.includes('already been destroyed')) {
// idempotent cleanup: safe to ignore
} else throw err;
} Prevention
- Make destroy paths idempotent with a local destroyed flag or wrapper
- Unsubscribe disconnect handlers before destroying
- Avoid keeping long-lived references that outlive the connection's lifecycle
When it happens
Trigger: Calling connection.destroy() twice — e.g. from both a disconnect handler and cleanup code, or after reconnection logic already destroyed the old connection.
Common situations: Double cleanup in shutdown paths (SIGINT handler + voiceStateUpdate), calling destroy() after subscribe/on('destroyed') already ran, or shared references to a stale connection object.
Related errors
- Session not available
- No session available
- ClientNotReady
- Session not available
- No compatible encryption modes. Available include: ${options
AI-assisted analysis of discordjs/discord.js@a81ed8a306 (2026-08-30).
Data as JSON: /api/errors/184cb372001315d3.
Report an issue: GitHub.