Skip to content

fix: catch ClosedResourceError when sending error log to disconnected client#2184

Open
giulio-leone wants to merge 1 commit intomodelcontextprotocol:mainfrom
giulio-leone:fix/client-disconnect-closed-resource-error
Open

fix: catch ClosedResourceError when sending error log to disconnected client#2184
giulio-leone wants to merge 1 commit intomodelcontextprotocol:mainfrom
giulio-leone:fix/client-disconnect-closed-resource-error

Conversation

@giulio-leone
Copy link

Summary

Fixes #2064

When a client disconnects during request handling in a stateless streamable-HTTP server, _handle_message's error handler tries to call send_log_message() back to the client. Since the write stream is already closed, this raises ClosedResourceError, which is unhandled and crashes the stateless session with an ExceptionGroup.

Root Cause

This is a different code path from what PR #1384 fixed. That PR addressed ClosedResourceError in the message router loop. This bug is in the error recovery path:

ClientDisconnect → _handle_message catches Exception
  → tries send_log_message() to notify client
  → write stream already closed → ClosedResourceError
  → unhandled in TaskGroup → ExceptionGroup crash

Fix

Added try/except around send_log_message() in _handle_message to catch both ClosedResourceError and BrokenResourceError, logging a debug message instead of crashing. Failing to notify a disconnected client is expected and harmless.

Tests

Added 3 tests to test_lowlevel_exception_handling.py:

  • test_exception_handling_tolerates_closed_write_stream[closed] — ClosedResourceError
  • test_exception_handling_tolerates_closed_write_stream[broken] — BrokenResourceError
  • test_exception_handling_reraises_with_closed_stream — original exception still re-raised when raise_exceptions=True

All 9 tests pass.

… client

When a client disconnects during request handling, _handle_message's
error handler tries to send_log_message() back to the client. Since the
write stream is already closed, this raises ClosedResourceError (or
BrokenResourceError), which is unhandled and crashes the stateless
session with an ExceptionGroup.

This is a different code path from what PR modelcontextprotocol#1384 fixed (message router
loop). This bug is in the error recovery path: catch exception → try to
log it to client → write stream already closed → crash.

Added try/except around send_log_message() to catch both
ClosedResourceError and BrokenResourceError, logging a debug message
instead of crashing.

Fixes modelcontextprotocol#2064

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@giulio-leone
Copy link
Author

Friendly ping — CI is green and this is ready for review. Happy to address any feedback. Thanks!

@giulio-leone
Copy link
Author

All CI checks pass. Ready for review.

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.

ClientDisconnect during _handle_post_request crashes stateless session with ClosedResourceError

1 participant