fix(VoiceConnection): handle close codes that should not reconnect (#11567)

* fix(VoiceConnection): handle close codes that should not reconnect

* docs(VoiceConnection): update close code documentation

---------

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
This commit is contained in:
けんちる / Kento Watanabe
2026-07-17 08:02:47 +09:00
committed by GitHub
parent 9771d9ef55
commit c73e2a76d1
2 changed files with 15 additions and 13 deletions
@@ -377,17 +377,17 @@ describe('VoiceConnection#onNetworkingClose', () => {
expect(adapter.sendPayload).not.toHaveBeenCalled();
});
test('Disconnects for code 4014', () => {
test.each([4_014, 4_021, 4_022])('Disconnects for close code %i', (code) => {
const { voiceConnection, adapter } = createFakeVoiceConnection();
voiceConnection['onNetworkingClose'](4_014);
voiceConnection['onNetworkingClose'](code);
expect(voiceConnection.state).toMatchObject({
status: VoiceConnectionStatus.Disconnected,
closeCode: 4_014,
closeCode: code,
});
expect(adapter.sendPayload).not.toHaveBeenCalled();
});
test('Attempts rejoin for codes != 4014', () => {
test('Attempts rejoin for close codes that should reconnect', () => {
const dummyPayload = Symbol('dummy') as any;
const { voiceConnection, adapter, joinConfig } = createFakeVoiceConnection();
DataStore.createJoinVoiceChannelPayload.mockImplementation((config) =>
@@ -399,7 +399,7 @@ describe('VoiceConnection#onNetworkingClose', () => {
expect(voiceConnection.rejoinAttempts).toEqual(1);
});
test('Attempts rejoin for codes != 4014 (with adapter failure)', () => {
test('Attempts rejoin for close codes that should reconnect (with adapter failure)', () => {
const dummyPayload = Symbol('dummy') as any;
const { voiceConnection, adapter, joinConfig } = createFakeVoiceConnection();
DataStore.createJoinVoiceChannelPayload.mockImplementation((config) =>
+10 -8
View File
@@ -451,21 +451,23 @@ export class VoiceConnection extends EventEmitter {
}
/**
* Called when the networking instance for this connection closes. If the close code is 4014 (do not reconnect),
* the voice connection will transition to the Disconnected state which will store the close code. You can
* decide whether or not to reconnect when this occurs by listening for the state change and calling reconnect().
* Called when the networking instance for this connection closes. If the close code is 4014, 4021, or 4022
* (do not reconnect), the voice connection will transition to the Disconnected state which will store the
* close code. You can decide whether or not to reconnect when this occurs by listening for the state change
* and calling reconnect().
*
* @remarks
* If the close code was anything other than 4014, it is likely that the closing was not intended, and so the
* VoiceConnection will signal to Discord that it would like to rejoin the channel. This automatically attempts
* to re-establish the connection. This would be seen as a transition from the Ready state to the Signalling state.
* If the close code was anything other than 4014, 4021, or 4022, it is likely that the closing was not intended,
* and so the VoiceConnection will signal to Discord that it would like to rejoin the channel. This automatically
* attempts to re-establish the connection. This would be seen as a transition from the Ready state to the
* Signalling state.
* @param code - The close code
*/
private onNetworkingClose(code: number) {
if (this.state.status === VoiceConnectionStatus.Destroyed) return;
// If networking closes, try to connect to the voice channel again.
if (code === 4_014) {
// Disconnected - networking is already destroyed here
if (code === 4_014 || code === 4_021 || code === 4_022) {
// Disconnected - these close codes should not trigger a reconnect
this.state = {
...this.state,
status: VoiceConnectionStatus.Disconnected,