From aa5bef6a9fec92bed1d9a53d92546cae4e75b351 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 17 Jul 2025 23:59:36 +0200 Subject: [PATCH 1/3] fix(llc): adjust WebSocket disconnect order to prevent race conditions This commit addresses a race condition that could occur during the WebSocket disconnection process. The issue stemmed from the order of operations: 1. User was reset (`_user = null`). 2. Event monitoring was stopped. This order could lead to a situation where an reconnection was processed after the user was already null, causing a crash. The fix reverses this order: 1. Event monitoring is stopped (`_stopMonitoringEvents()`). 2. User is reset. This ensures that no reconnect attempts are made after the user object has been cleared, preventing the race condition. --- packages/stream_chat/lib/src/ws/websocket.dart | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/packages/stream_chat/lib/src/ws/websocket.dart b/packages/stream_chat/lib/src/ws/websocket.dart index f4c4cd875..6f77a2251 100644 --- a/packages/stream_chat/lib/src/ws/websocket.dart +++ b/packages/stream_chat/lib/src/ws/websocket.dart @@ -475,21 +475,18 @@ class WebSocket with TimerHelper { /// Disconnects the WS and releases eventual resources void disconnect() { if (connectionStatus == ConnectionStatus.disconnected) return; - - _resetRequestFlags(resetAttempts: true); - _connectionStatus = ConnectionStatus.disconnected; _logger?.info('Disconnecting web-socket connection'); + _manuallyClosed = true; + _resetRequestFlags(resetAttempts: true); + _stopMonitoringEvents(); + // resetting user _user = null; connectionCompleter = null; - _stopMonitoringEvents(); - - _manuallyClosed = true; - _closeWebSocketChannel(); } } From 584e5e8ba70871c670dc1f30493044acb6561f6f Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 18 Jul 2025 00:08:49 +0200 Subject: [PATCH 2/3] chore: add extra user null check --- packages/stream_chat/lib/src/ws/websocket.dart | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/stream_chat/lib/src/ws/websocket.dart b/packages/stream_chat/lib/src/ws/websocket.dart index 6f77a2251..4a339a423 100644 --- a/packages/stream_chat/lib/src/ws/websocket.dart +++ b/packages/stream_chat/lib/src/ws/websocket.dart @@ -263,6 +263,12 @@ class WebSocket with TimerHelper { setTimer( Duration(milliseconds: delay), () async { + // If the user is null, it means either the connection was never + // established or it was disconnected manually. + // + // In either case, we should not attempt to reconnect. + if (_user == null) return; + final uri = await _buildUri( refreshToken: refreshToken, includeUserDetails: false, From ad5bc96b88768aaa8d55a826d54c76060e3e977c Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 18 Jul 2025 00:12:12 +0200 Subject: [PATCH 3/3] chore: update CHANGELOG.md --- packages/stream_chat/CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/stream_chat/CHANGELOG.md b/packages/stream_chat/CHANGELOG.md index 039f16321..298468ba2 100644 --- a/packages/stream_chat/CHANGELOG.md +++ b/packages/stream_chat/CHANGELOG.md @@ -1,3 +1,9 @@ +## Upcoming + +🐞 Fixed + +- Fixed `WebSocket` race condition where reconnection could access null user during disconnect. + ## 9.14.0 🐞 Fixed