Bug
`SlackAdapter.connect()` overwrites `self._handler`, `self._app`, and `self._socket_mode_task` without closing the previous ones first. If `connect()` is called a second time on the same adapter (e.g., during a gateway restart or in-process reconnect attempt), the old `AsyncSocketModeHandler` and its background task remain alive with an open Socket Mode websocket. Both the old and new connections receive every incoming Slack event, dispatching it twice — producing double responses with different wording, similar to #18187 (which was the same bug in `DiscordAdapter`).
Root Cause
`gateway/platforms/slack.py` `connect()` (line ~533):
```python
self._app = AsyncApp(token=primary_token) # old _app ref dropped, not closed
...
self._handler = AsyncSocketModeHandler(...) # old _handler ref dropped, not closed
self._socket_mode_task = asyncio.create_task(...) # old task orphaned, still running
```
There is no guard equivalent to the one `DiscordAdapter.connect()` gained in #18758 (merged today).
Fix
Add the same close-before-reassign guard at the top of `SlackAdapter.connect()`:
```python
if self._socket_mode_task and not self._socket_mode_task.done():
self._socket_mode_task.cancel()
try:
await self._socket_mode_task
except asyncio.CancelledError:
pass
self._socket_mode_task = None
if self._handler is not None:
try:
await self._handler.close_async()
except Exception:
logger.debug("[%s] Failed to close previous Slack handler", self.name)
finally:
self._handler = None
self._app = None
```
Parity fix — adds the same guard that `DiscordAdapter.connect()` already has.
Bug
`SlackAdapter.connect()` overwrites `self._handler`, `self._app`, and `self._socket_mode_task` without closing the previous ones first. If `connect()` is called a second time on the same adapter (e.g., during a gateway restart or in-process reconnect attempt), the old `AsyncSocketModeHandler` and its background task remain alive with an open Socket Mode websocket. Both the old and new connections receive every incoming Slack event, dispatching it twice — producing double responses with different wording, similar to #18187 (which was the same bug in `DiscordAdapter`).
Root Cause
`gateway/platforms/slack.py` `connect()` (line ~533):
```python
self._app = AsyncApp(token=primary_token) # old _app ref dropped, not closed
...
self._handler = AsyncSocketModeHandler(...) # old _handler ref dropped, not closed
self._socket_mode_task = asyncio.create_task(...) # old task orphaned, still running
```
There is no guard equivalent to the one `DiscordAdapter.connect()` gained in #18758 (merged today).
Fix
Add the same close-before-reassign guard at the top of `SlackAdapter.connect()`:
```python
if self._socket_mode_task and not self._socket_mode_task.done():
self._socket_mode_task.cancel()
try:
await self._socket_mode_task
except asyncio.CancelledError:
pass
self._socket_mode_task = None
if self._handler is not None:
try:
await self._handler.close_async()
except Exception:
logger.debug("[%s] Failed to close previous Slack handler", self.name)
finally:
self._handler = None
self._app = None
```
Parity fix — adds the same guard that `DiscordAdapter.connect()` already has.