Skip to content

fix(websocket): Raise IOException on closed connection instead of returning b""#1213

Merged
acul71 merged 4 commits intomainfrom
fix/websocket-closure-detection
Feb 14, 2026
Merged

fix(websocket): Raise IOException on closed connection instead of returning b""#1213
acul71 merged 4 commits intomainfrom
fix/websocket-closure-detection

Conversation

@acul71
Copy link
Contributor

@acul71 acul71 commented Feb 13, 2026

Summary

Fixes #1212

  • WebSocket read() now raises IOException when the connection is closed, instead of returning b"". This allows read_exactly() to immediately detect closure instead of retrying up to 100 times on empty bytes.
  • Yamux send_window_update() gracefully handles connection closure errors during window updates — when the peer closes the connection between reading data and sending the window update (common with Nim, JVM, rust-v0.53), the error is logged at debug level instead of crashing, since the data was already read successfully.
  • Improved _extract_close_info() fallback to handle mock exceptions and non-standard exception types with code/reason directly on the exception object.
  • Added outer catch-all in read() for connection closure exceptions missed by inner handlers.
  • Exception chaining (from e) in write() for better tracebacks.

Background

This is a fresh, minimal implementation based on current main. The original PR #1083 (addressing issue #1082) was 335 commits behind main with 3 merge conflicts, and ~50% of its changes had already landed via PR #964 and PR #1114. This PR carries forward only the remaining unfixed bugs.

Test plan

  • make lint — all checks pass
  • make typecheck — mypy and pyrefly pass
  • make test — 2091 passed, 16 skipped, 0 failures
  • make linux-docs — docs build + 109 doctests pass
  • New unit tests for send_window_update() error handling (7 tests)
  • New unit tests for WebSocket closure detection (5 tests)
  • Newsfragment 1212.bugfix.rst included

Made with Cursor

acul71 and others added 4 commits February 13, 2026 20:21
…urning b""

Fixes #1212

- WebSocket read() now raises IOException when connection is closed,
  allowing read_exactly() to immediately detect closure instead of
  retrying 100 times on empty bytes
- Yamux send_window_update() gracefully handles connection closure
  errors during window updates (data was already read successfully)
- Improved _extract_close_info() fallback for non-standard exceptions
- Added exception chaining (from e) in write() for better tracebacks
- Comprehensive test suite for closure handling scenarios

Co-authored-by: Cursor <cursoragent@cursor.com>
…ectionClosedError

Add ConnectionClosedError(IOException) with structured close_code,
close_reason, and transport attributes.  The WebSocket transport now
raises this typed exception instead of a plain IOException with the
close info buried in the message string.  Yamux catches it by type
(`except ConnectionClosedError`) instead of parsing `str(e).lower()`
for closure keywords — eliminating a fragile pattern that would
silently break if anyone changed an error message.

A string-matching fallback is retained for transports that don't yet
raise ConnectionClosedError (e.g. TCP RawConnError).

Co-authored-by: Cursor <cursoragent@cursor.com>
@acul71 acul71 merged commit e4ca2e1 into main Feb 14, 2026
74 of 75 checks passed
@acul71 acul71 deleted the fix/websocket-closure-detection branch February 14, 2026 00:45
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.

fix(websocket): WebSocket read() returns b"" on closed connection instead of raising IOException

1 participant

Comments