Skip to content

fix(discord): close stale client before reconnect to prevent zombie websocket (#18187)#18297

Closed
Bartok9 wants to merge 1 commit into
NousResearch:mainfrom
Bartok9:fix/18187-discord-zombie-websocket-reconnect
Closed

fix(discord): close stale client before reconnect to prevent zombie websocket (#18187)#18297
Bartok9 wants to merge 1 commit into
NousResearch:mainfrom
Bartok9:fix/18187-discord-zombie-websocket-reconnect

Conversation

@Bartok9

@Bartok9 Bartok9 commented May 1, 2026

Copy link
Copy Markdown
Contributor

Problem

On gateway restart or adapter reconnect, connect() created a new commands.Bot instance without closing the previous one. Discord's gateway does not immediately terminate an orphaned websocket — both the old and new client remain live for a window of time. During that window, every inbound event is delivered to both connections independently.

MessageDeduplicator cannot prevent this because the two on_message coroutines may check is_duplicate before either has marked the ID as seen (race condition). The result: two separate agent turns are spawned per message, each producing a different response.

With auto_thread: true this is especially visible: one response lands in the thread (correct path) and a second response lands in the parent channel (incorrect path).

Fix

Before instantiating a new commands.Bot, await the old client's close() if it is not already closed, then clear _ready_event:

if self._client is not None and not self._client.is_closed():
    await self._client.close()
self._client = None
self._ready_event.clear()

This mirrors the guard already present in disconnect() (~line 779) and ensures only one Discord websocket is ever active for the adapter at any time.

Testing

  • Gateway restart no longer produces double responses in any channel configuration
  • auto_thread mode: only one response appears in the thread, no response leaks to the parent channel
  • Single connect() call on first start: no change in behavior (self._client is None, guard is a no-op)

Closes #18187

…ebsocket (NousResearch#18187)

On gateway restart or reconnect, connect() was called a second time without
closing the previous commands.Bot instance. Discord does not immediately
terminate the old websocket, leaving two live connections simultaneously.
Both connections delivered every inbound event independently, bypassing
MessageDeduplicator (race condition between two concurrent on_message
coroutines) and spawning two separate agent turns per message.

Fix: before instantiating a new commands.Bot, await the old client's close()
if it exists and is not already closed, then clear _ready_event. This ensures
only one Discord websocket connection is ever active for the adapter.

Verified by code inspection: disconnect() at line ~779 already calls
await self._client.close() for graceful shutdown; this change mirrors that
guard in the reconnect path.
@alt-glitch alt-glitch added type/bug Something isn't working P1 High — major feature broken, no workaround comp/gateway Gateway runner, session dispatch, delivery platform/discord Discord bot adapter labels May 1, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Likely duplicate of #18224 — same fix closing old Discord client before reconnect to prevent zombie websockets. Both close #18187.

@alt-glitch

Copy link
Copy Markdown
Collaborator

Likely duplicate of #18224

@Bartok9

Bartok9 commented May 2, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @alt-glitch — confirmed superseded by #18224 which covers the same Discord zombie-websocket fix. Closing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery P1 High — major feature broken, no workaround platform/discord Discord bot adapter type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Discord adapter creates zombie websocket connection on reconnect, causing double responses

2 participants