Conversation
Add a `connectGeneration` counter to prevent stale `stateUpdateHandler` closures from resuming an already-completed `CheckedContinuation`. The crash occurred when: 1. connect() modelcontextprotocol#1 succeeds — continuation A is resumed via .ready 2. Connection breaks — receiveLoop calls connection.cancel() 3. cancel() triggers the old stateUpdateHandler, which queues a Task capturing continuation A 4. receiveLoop calls connect() modelcontextprotocol#2, resetting `connectionContinuationResumed` to false and creating continuation B 5. The queued Task from step 3 checks the flag (now false), passes the guard, and tries to resume continuation A — which was already resumed in step 1 → SIGTRAP (CheckedContinuation double-resume assertion) The fix increments a generation counter on each connect() call. Each stateUpdateHandler closure captures its generation, and handler methods verify the generation matches before touching the continuation. Also fixes Swift 6 strict concurrency warnings in ClientTests (mutable local variables captured in Sendable closures). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
5 tasks
This was referenced Sep 10, 2026
ianegordon
added a commit
to ianegordon/swift-sdk
that referenced
this pull request
Sep 12, 2026
Issue titles are now bare 'Upstream PR#<n>'; the merge/investigate/decline label carries the decision, so the title does not duplicate it. Two places named the old convention and are updated. The investigate count was also stale: it said twelve, which was true at triage on 2026-09-10. Four were declined since (modelcontextprotocol#280, modelcontextprotocol#226, modelcontextprotocol#118, modelcontextprotocol#204) and two were promoted and merged (modelcontextprotocol#266 as entries 9/9a, modelcontextprotocol#275 as 10/10a/10b), leaving six — modelcontextprotocol#178, modelcontextprotocol#213, modelcontextprotocol#216, modelcontextprotocol#257, modelcontextprotocol#258, modelcontextprotocol#259 — now listed by number rather than by count, so the sentence cannot drift again. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Eb9yGSXH1TVkg5Afsu9phk
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.
Summary
EXC_BREAKPOINT/SIGTRAPcrash caused byCheckedContinuationbeing resumed twice during NetworkTransport reconnectionconnectGenerationcounter that invalidates stalestateUpdateHandlerclosures from previousconnect()cyclesClientTests.swiftRoot cause
When a connection breaks and
receiveLoopinitiates reconnection, it callsconnection.cancel()followed byconnect(). Thecancel()triggers thestateUpdateHandlerfrom the firstconnect()cycle, which queues a Task capturing the old continuation. Meanwhile, the newconnect()resetsconnectionContinuationResumedtofalseand creates a new continuation.When the queued Task from the old handler finally runs, it checks the flag (now
falsedue to the reset), passes the guard, and attempts to resume the old continuation — which was already resumed successfully via.readyin the first cycle. This triggers Swift'sCheckedContinuationdouble-resume assertion (SIGTRAP).Fix
A
connectGenerationcounter (UInt64) is incremented on eachconnect()call and captured in thestateUpdateHandlerclosure. All handler methods (handleConnectionReady,handleConnectionFailed,handleConnectionCancelled) verify the generation matches before proceeding. Stale handlers from previous cycles are logged and safely ignored.Test plan
NetworkTransportTestspass (including the new regression test)testStaleHandlerDoesNotDoubleResumeverifies the specific crash scenario~/Library/Logs/DiagnosticReports/iMCP-2026-03-28-*.ips) showing identical stack traces🤖 Generated with Claude Code