Fix: swallow _receiveTask exceptions in SseClientSessionTransport.CloseAsync#1432
Open
xue-cai wants to merge 5 commits into
Open
Fix: swallow _receiveTask exceptions in SseClientSessionTransport.CloseAsync#1432xue-cai wants to merge 5 commits into
xue-cai wants to merge 5 commits into
Conversation
…seAsync
When SseClientSessionTransport.ConnectAsync fails (e.g. server returns 405),
the catch block calls CloseAsync() before wrapping the error in
InvalidOperationException. However, CloseAsync() awaits the already-faulted
_receiveTask without a try-catch, causing the original HttpRequestException
to propagate out of CloseAsync and preempt the InvalidOperationException
wrapping. Callers then receive a bare HttpRequestException instead of the
documented InvalidOperationException("Failed to connect transport", ex).
The fix wraps `await _receiveTask` in CloseAsync with a try-catch to
swallow already-observed exceptions from the faulted task.
Code references:
SseClientSessionTransport.ConnectAsync (catch block calls CloseAsync):
https://github.com/modelcontextprotocol/csharp-sdk/blob/v0.9.0-preview.2/src/ModelContextProtocol.Core/Client/SseClientSessionTransport.cs#L52-L67
SseClientSessionTransport.CloseAsync (awaits _receiveTask without try-catch):
https://github.com/modelcontextprotocol/csharp-sdk/blob/v0.9.0-preview.2/src/ModelContextProtocol.Core/Client/SseClientSessionTransport.cs#L108-L130
Testing:
# Build all frameworks (only netstandard2.0 fails — pre-existing on main):
dotnet build tests/ModelContextProtocol.Tests/ '/p:NoWarn=NU1903%3BMCPEXP001'
# Run full transport suite (74 tests × 3 frameworks = 222 total, 0 failures):
dotnet test tests/ModelContextProtocol.Tests/ '/p:NoWarn=NU1903%3BMCPEXP001' --no-build --filter "FullyQualifiedName~Transport" --framework net10.0
dotnet test tests/ModelContextProtocol.Tests/ '/p:NoWarn=NU1903%3BMCPEXP001' --no-build --filter "FullyQualifiedName~Transport" --framework net9.0
dotnet test tests/ModelContextProtocol.Tests/ '/p:NoWarn=NU1903%3BMCPEXP001' --no-build --filter "FullyQualifiedName~Transport" --framework net8.0
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
xue-cai
force-pushed
the
fix/sse-connect-close-exception-swallow
branch
from
March 17, 2026 01:29
9b21522 to
056f1f5
Compare
halter73
reviewed
Mar 19, 2026
Contributor
|
Not exactly related to this PR, but I can't unsee the incorrect InvalidOperationException we throw from line 65. Can we turn that into just a |
…-exception-swallow # Conflicts: # tests/ModelContextProtocol.Tests/Transport/HttpClientTransportAutoDetectTests.cs
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Contributor
|
This will be a subtle breaking change because of changing the exception types thrown. We'll capture it in the release notes. Thanks for getting this PR started, @xue-cai. |
jeffhandley
approved these changes
Jul 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
When
SseClientSessionTransport.ConnectAsyncfails (for example, an SSE GET returns 405),ReceiveMessagesAsyncreports the failure through_connectionEstablishedand the connection path closes the transport.Previously,
ReceiveMessagesAsyncrethrew after reporting that failure. This faulted_receiveTask, soCloseAsynccould rethrow the same exception while awaiting it and preempt the original connection-failure path.The fix leaves the receive task completed after recording and logging the failure, allowing
CloseAsyncto await it normally.ConnectAsyncthen rethrows the original exception after cleanup rather than adding an inaccurate wrapper.The regression coverage verifies direct SSE failures preserve their original exception, and that auto-detection preserves the initial Streamable HTTP error while retaining the SSE fallback failure as its inner exception.