Skip to content

fix(llc): ignore the ws channel ready future on connect - #2927

Merged
xsahil03x merged 2 commits into
masterfrom
fix/ws-ready-unhandled-error
Aug 26, 2026
Merged

fix(llc): ignore the ws channel ready future on connect#2927
xsahil03x merged 2 commits into
masterfrom
fix/ws-ready-unhandled-error

Conversation

@xsahil03x

@xsahil03x xsahil03x commented Aug 26, 2026

Copy link
Copy Markdown
Member

Submit a pull request

Linear: FLU-
Closes: #2921

CLA

  • I have signed the Stream CLA (required).
  • The code changes follow best practices
  • Code changes are tested

Description of the pull request

AdapterWebSocketChannel reports a connect failure on three futures:

}, onError: (Object e) {
  error = WebSocketChannelException.from(e);
  _readyCompleter.completeError(error);    // 1. channel.ready
  _controller.local.sink.addError(error);  // 2. channel.stream
  _controller.local.sink.close();          // 3. sink.done
});

_initWebSocketChannel handled (2) via onError: _onConnectionError and (3) via the existing sink.done.ignore(), but never listened to (1). A Future completed with an error and never listened to is reported to Zone.current.handleUncaughtError — in a Flutter app, PlatformDispatcher.onError — so apps routing that into a crash reporter saw every failed connect as a fatal crash:

Fatal Exception: io.flutter.plugins.firebase.crashlytics.FlutterError
WebSocketChannelException: SocketException: Failed host lookup: 'chat.stream-io-api.com'

Reconnect behaviour was never affected — the error is handled by _onConnectionError, and the orphan is a silent duplicate that only shows up once a zone / PlatformDispatcher error handler is installed. That is why #2304 looked non-reproducible in a debug run. Report volume is high because _reconnect builds a fresh channel per attempt (up to maxReconnectAttempts, default 6) and _ChatLifecycleManager calls maybeReconnect() on every foreground and connectivity change.

The fix is one line, next to the existing one and for the same reason:

_webSocketChannel?.ready.ignore();
_webSocketChannel?.sink.done.ignore();

How this was verified

Against an unresolvable host, mirroring _initWebSocketChannel + _subscribeToWebSocketChannel and counting errors that reach a zone handler:

before -> streamErrors: 1, onDone: 1, unhandled: 1
after  -> streamErrors: 1, onDone: 1, unhandled: 0

stream.onError still receives its copy — .ignore() on ready only marks that future handled, it does not consume the stream's delivery.

_closeWebSocketChannel was checked for the same failure class (closing a failed channel, a healthy one, one the server already dropped, and a sink.add on a dead channel): zero orphans in all four, because sink.close() hands back the same future as done, which is already ignored. No change needed there.

Credit to @jm-harman for the diagnosis in #2921.

Test coverage

Added `connect` does not orphan the channel `ready` error — stubs ready to complete with an error and asserts the SDK reads it, with a pumpEventQueue() guard so a future regression that reads ready but drops the result also fails. Reverting the fix makes the test fail. Full stream_chat suite passes (1626 tests).

Screenshots / Videos

Not applicable — no UI change.

🤖 Generated with Claude Code

Summary by CodeRabbit

Bug Fixes

  • Fixed failed WebSocket connections being reported as unhandled fatal errors.
  • Prevented duplicate connection-failure notifications when a WebSocket connection cannot be established.
  • Improved error handling so connection failures are handled cleanly without orphaned errors.

Improvements

  • Updated message translation handling to preserve existing channel state.
  • Added support for Dart SDK version 3.12.0 and newer.

Deprecations

  • Deprecated message and user unflagging methods in favor of newer alternatives.

`AdapterWebSocketChannel` reports a connect failure on three futures:
`ready`, the stream, and `sink.done`. `_initWebSocketChannel` handled the
last two but never listened to `ready`, so every failed connect left an
errored future in the root zone. Apps routing
`PlatformDispatcher.onError` into a crash reporter saw each one as a
fatal crash, up to `maxReconnectAttempts` per outage.

Closes #2921

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a67fcaa6-72f1-4fc3-b042-b49b1e02b2fb

📥 Commits

Reviewing files that changed from the base of the PR and between 18c1148 and b475430.

📒 Files selected for processing (1)
  • packages/stream_chat/CHANGELOG.md

Included review availability: Your plan provides up to 4 included reviews per hour; 3 remain after this review.


📝 Walkthrough

Walkthrough

Changes

WebSocket error handling

Layer / File(s) Summary
Consume ready future errors
packages/stream_chat/lib/src/ws/websocket.dart, packages/stream_chat/CHANGELOG.md
The WebSocket initializer ignores ready errors in addition to sink.done errors. The changelog records the fix.
Verify failed connection handling
packages/stream_chat/test/src/ws/websocket_test.dart
Tests stub successful ready futures and verify that a failed ready future is read once without creating an unhandled zone error.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to b4754

This localized change prevents duplicate connection errors from being reported as uncaught application failures without changing reconnect or stream behavior; no actionable merge-blocking risk remains after normal checks and review.

Suggested reviewers: velikovpetar

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: ignoring the WebSocket channel's ready future during connection initialization.
Linked Issues check ✅ Passed The changes satisfy issue #2921 by ignoring WebSocketChannel.ready alongside sink.done and adding a regression test that verifies the ready error is handled without an unhandled zone error.
Out of Scope Changes check ✅ Passed The code, regression test, and changelog updates are directly related to the WebSocket error-handling fix. No unrelated changes are present.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0…
Full details: Docstring Coverage

Explanation

No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0 files. (1 skipped: 1 unsupported.)

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/ws-ready-unhandled-error

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Aug 26, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 74.18%. Comparing base (e53b78b) to head (b475430).

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #2927   +/-   ##
=======================================
  Coverage   74.17%   74.18%           
=======================================
  Files         437      437           
  Lines       28373    28374    +1     
=======================================
+ Hits        21047    21048    +1     
  Misses       7326     7326           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@xsahil03x
xsahil03x enabled auto-merge (squash) August 26, 2026 12:51
@xsahil03x
xsahil03x merged commit 78c3f8d into master Aug 26, 2026
31 checks passed
@xsahil03x
xsahil03x deleted the fix/ws-ready-unhandled-error branch August 26, 2026 13:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

WebSocketChannel.ready error is never handled: every failed connect orphans an unhandled exception (root cause for #2304)

2 participants