If your Discord bot loses its voice connection after approximately two minutes of silence, you are encountering a built-in idle timeout enforced by Discord. This timeout is designed to free server resources when no audio data is being transmitted. The disconnection is not a bug or a hardware problem — it is a deliberate behavior of Discord’s voice gateway. This article explains the technical mechanism behind the 2-minute idle disconnect and provides concrete coding strategies to keep your bot connected.
Key Takeaways: Keeping Your Discord Bot Voice Channel Active
- discord.py voice_client.idle_timeout: The internal timer that triggers disconnect after 120 seconds of silence.
- discord.py VoiceClient.play() with silence audio: Sending a silent audio frame resets the idle timer without audible noise.
- discord.js VoiceConnection.receiver.speaking.started event: A listener that can reset the idle timeout when users speak.
Why Discord Disconnects Idle Bot Voice Connections After 2 Minutes
Discord’s voice infrastructure uses a WebSocket-based gateway to stream real-time audio. Each voice connection maintains a state machine that tracks whether audio is actively being sent or received. When no audio packets are transmitted for 120 seconds, Discord’s server closes the WebSocket connection with a specific close code (4015 for idle timeout). This behavior conserves bandwidth and processing power on Discord’s side, especially in large servers where many bots might otherwise hold open connections indefinitely.
The timeout applies to both user clients and bot accounts, but users rarely notice because they are usually in active conversation. Bots, however, often sit silently in a channel waiting for a command. The idle timer resets each time the bot sends an audio packet (even a silent one) or receives audio from another user. Simply being in the channel does not reset the timer — the bot must actively participate in the audio stream.
Technical Details of the Idle Timeout
The timeout is enforced at the Discord voice gateway level, not within the bot library. The relevant gateway opcode is Voice Speaking (opcode 5) and the Voice Heartbeat (opcode 3). Heartbeats keep the WebSocket alive but do not reset the idle timer. Only audio data (PCM frames) resets it. In discord.py, the VoiceClient object has an internal attribute idle_timeout (default 120 seconds) and a _idle_timer that triggers disconnect() when the timeout expires. In discord.js, the VoiceConnection emits a disconnect event with the reason idle.
Steps to Prevent Idle Disconnection in discord.py
The most reliable method is to send a silent audio frame at intervals shorter than 120 seconds. Below is a complete implementation using discord.py 2.x.
- Import required modules
Add these imports at the top of your bot script:import discord, asyncio, struct, io. You needstructto build the silent PCM frame andiofor theFFmpegPCMAudiosource. - Create a silent audio source
Define a function that returns adiscord.FFmpegPCMAudioobject playing a silent WAV file. The simplest approach is to generate a 20-millisecond silent PCM frame in memory. Usediscord.FFmpegPCMAudio(io.BytesIO(silent_wav_bytes))wheresilent_wav_bytesis a valid WAV header plus 1764 bytes of zeros (44.1 kHz, 16-bit, mono). - Start a background task to play silence
After connecting to a voice channel, launch anasyncio.create_taskthat loops every 60 seconds. Inside the loop, callvoice_client.play(silent_source). This resets the idle timer. The task should catchasyncio.CancelledErrorwhen the bot disconnects. - Cancel the task on disconnect
Override theon_voice_state_updateevent to detect when the bot leaves the channel. Cancel the background task usingtask.cancel()to avoid resource leaks. - Test the connection
Join a voice channel with your bot and wait 3 minutes. The bot should remain connected. Verify by checking thevoice_client.is_connected()status.
Steps to Prevent Idle Disconnection in discord.js
In discord.js, you can use the VoiceConnection receiver to detect when users speak and reset the timeout, or send silent frames using createAudioResource with a silent file.
- Install dependencies
Ensure you have@discordjs/voiceandffmpeg-staticinstalled. Runnpm install @discordjs/voice ffmpeg-static. - Create a silent audio resource
Create a 20-millisecond silent WAV file using Node.jsfsandchild_process. Alternatively, use a pre-generated silent file in your project folder. Load it withcreateAudioResource('silence.wav'). - Play silence in a loop
After joining a channel withjoinVoiceChannel, useplayer.play(resource)inside asetIntervalthat runs every 60 seconds. Useplayer.stop()before playing to avoid overlapping audio. - Clean up interval on disconnect
Listen for thestateChangeevent on theVoiceConnection. When the status becomesVoiceConnectionStatus.Disconnected, clear the interval withclearInterval.
If the Bot Still Disconnects After Applying the Main Fix
Bot Disconnects Due to Network Latency Spikes
Even if you send silent frames, a sudden network issue can cause the WebSocket to close. Check your bot’s ping to Discord using voice_client.ping in discord.py or voiceConnection.ping in discord.js. If ping exceeds 500 ms, the gateway may disconnect. Use a server closer to Discord’s voice regions, or implement a reconnection loop that calls voice_client.connect() again.
Bot Disconnects After a Discord Update
Discord occasionally changes the idle timeout duration or the close code. In 2023, the timeout was reduced from 3 minutes to 2 minutes for some regions. Always check the Discord Developer Voice Connections documentation for the latest timeout values. Update your bot library to the latest version to handle any new close codes.
Bot Disconnects When No Users Are in the Channel
The idle timeout applies regardless of how many users are present. If your bot is alone in a channel, the same 2-minute rule applies. The silent frame method works here too. For bots that only need to listen for commands, consider using a text channel trigger and joining the voice channel only when needed, then leaving after the command finishes. This avoids the idle timeout entirely.
Comparison: Idle Timeout Workarounds for discord.py vs discord.js
| Item | discord.py | discord.js |
|---|---|---|
| Silent frame method | Use FFmpegPCMAudio with a silent WAV in memory |
Use createAudioResource with a silent file |
| Loop mechanism | asyncio.create_task with while True and asyncio.sleep(60) |
setInterval with 60000 ms |
| Disconnect cleanup | Catch on_voice_state_update and cancel task |
Listen to stateChange event and clear interval |
| Receiver-based reset | Not natively supported; requires manual on_voice_state_update tracking |
Use VoiceConnection.receiver.speaking.started event |
| Library version tested | discord.py 2.3.2 | discord.js 14.14.1 with @discordjs/voice 0.17.0 |
Discord bots disconnect from voice channels after 2 minutes of idle activity due to a deliberate server-side timeout that conserves resources. You can prevent this by sending silent audio frames at regular intervals using the methods described above. For discord.py, use FFmpegPCMAudio with a silent WAV in a background task. For discord.js, use createAudioResource with a silent file in a setInterval. If the bot still disconnects, check network latency and update your library. A more advanced approach is to use the VoiceClient.reconnect() method to automatically rejoin the channel after an idle disconnect, though this may cause a brief interruption in audio.