Title: fix: catch ClosedResourceError in _handle_message error recovery path by herakles-dev · Pull Request #2242 · modelcontextprotocol/python-sdk · GitHub
Open Graph Title: fix: catch ClosedResourceError in _handle_message error recovery path by herakles-dev · Pull Request #2242 · modelcontextprotocol/python-sdk
X Title: fix: catch ClosedResourceError in _handle_message error recovery path by herakles-dev · Pull Request #2242 · modelcontextprotocol/python-sdk
Description: Summary When a client disconnects while a stateless streamable-HTTP server is reading the request body, _handle_message catches the stream exception but then tries to send_log_message() back to the already-disconnected client. Since the write stream is closed, this raises ClosedResourceError, which propagates unhandled and crashes the stateless session with an ExceptionGroup. This is a different code path from what PR #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. Fix Wrap the send_log_message() call in _handle_message with a try/except for anyio.ClosedResourceError and anyio.BrokenResourceError. This matches the existing pattern already used throughout streamable_http.py (lines 589, 915, 1011, 1020). Failing to notify a disconnected client is expected and harmless. Changes src/mcp/server/lowlevel/server.py — catch ClosedResourceError/BrokenResourceError around send_log_message() in the Exception branch of _handle_message, log at debug level instead of crashing tests/server/test_lowlevel_exception_handling.py — two regression tests: test_exception_handling_tolerates_closed_write_stream — parametrized over both error types, verifies no crash when send_log_message raises test_exception_handling_closed_stream_still_reraises_when_requested — verifies raise_exceptions=True still propagates the original error even when the write stream is closed Test plan New regression tests cover both ClosedResourceError and BrokenResourceError scenarios Existing exception handling tests continue to pass (no behavioral change for connected clients) raise_exceptions=True still correctly re-raises the original error after the log attempt fails Fixes #2064
Open Graph Description: Summary When a client disconnects while a stateless streamable-HTTP server is reading the request body, _handle_message catches the stream exception but then tries to send_log_message() back to the...
X Description: Summary When a client disconnects while a stateless streamable-HTTP server is reading the request body, _handle_message catches the stream exception but then tries to send_log_message() back to the...
Opengraph URL: https://github.com/modelcontextprotocol/python-sdk/pull/2242
X: @github
Domain: github.com
| route-pattern | /:user_id/:repository/pull/:id/files(.:format) |
| route-controller | pull_requests |
| route-action | files |
| fetch-nonce | v2:11a3af48-c1d5-824c-834b-8fdf30e0525d |
| current-catalog-service-hash | ae870bc5e265a340912cde392f23dad3671a0a881730ffdadd82f2f57d81641b |
| request-id | C7BA:D8AA8:4E2D39:680FEF:6A5B56AB |
| html-safe-nonce | 098164bc904dbfbfef3ce6042f04ff2331950e4b6494c66facc85f87ec2226c4 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJDN0JBOkQ4QUE4OjRFMkQzOTo2ODBGRUY6NkE1QjU2QUIiLCJ2aXNpdG9yX2lkIjoiODg5NDU1ODQ1MjA4MzAyMTQ4MyIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9 |
| visitor-hmac | ad7659bca690a952c265915af2881b144bfc43919097b7e9814a9bea5f875566 |
| hovercard-subject-tag | pull_request:3366604894 |
| github-keyboard-shortcuts | repository,pull-request-list,pull-request-conversation,pull-request-files-changed,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/modelcontextprotocol/python-sdk/pull/2242/files |
| twitter:image | https://avatars.githubusercontent.com/u/180692269?s=400&v=4 |
| twitter:card | summary_large_image |
| og:image | https://avatars.githubusercontent.com/u/180692269?s=400&v=4 |
| og:image:alt | Summary When a client disconnects while a stateless streamable-HTTP server is reading the request body, _handle_message catches the stream exception but then tries to send_log_message() back to the... |
| og:site_name | GitHub |
| og:type | object |
| hostname | github.com |
| expected-hostname | github.com |
| None | 5290d7e14309ad1e76106a9c4237bd1041517e83ea182c8ab756752cb0c6940b |
| turbo-cache-control | no-preview |
| diff-view | unified |
| go-import | github.com/modelcontextprotocol/python-sdk git https://github.com/modelcontextprotocol/python-sdk.git |
| octolytics-dimension-user_id | 182288589 |
| octolytics-dimension-user_login | modelcontextprotocol |
| octolytics-dimension-repository_id | 862584018 |
| octolytics-dimension-repository_nwo | modelcontextprotocol/python-sdk |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 862584018 |
| octolytics-dimension-repository_network_root_nwo | modelcontextprotocol/python-sdk |
| turbo-body-classes | logged-out env-production page-responsive full-width |
| disable-turbo | true |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 9c975978430e9ad293956f2bbdaf153b1bd84a99 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width