Skip to content

v1.4.0 crashes deterministically on macOS 26.4 in NetworkTransport.handleReconnection (CheckedContinuation double-resume) #167

@MySethPorter

Description

@MySethPorter

Summary

iMCP v1.4.0 (build 10) crashes on every launch on macOS 26.4. Same binary works on macOS 26.3.1.

The crash is a CheckedContinuation double-resume in the swift-sdk dependency's NetworkTransport.handleReconnection. macOS 26.4's Swift concurrency runtime is stricter about detecting this pattern, surfacing what was previously a latent bug.

Environment

  • iMCP: v1.4.0 (build 10), ad-hoc signed
  • swift-sdk: pinned by Package.resolved (verified the bug exists in Sources/MCP/Base/Transports/NetworkTransport.swift)
  • Crashing OS: macOS 26.4 (build 25E246)
  • Working OS: macOS 26.3.1 (build 25D771280a)
  • Hardware: arm64

Crash signature

EXC_BREAKPOINT / SIGTRAP at 0x000000019f363cc8
libswiftCore.dylib       _assertionFailure(_:_:file:line:flags:) + 172
libswift_Concurrency     CheckedContinuation.resume(throwing:) + 332
iMCP                     closure #1 in NetworkTransport.handleReconnection(error:continuation:context:) + 196
libswift_Concurrency     completeTaskWithClosure(...)

10 identical crashes observed in a single session, both on existing and freshly-reset container state. The crash signature is identical for the iMCP GUI binary and the imcp-server stdio binary.

Root cause

NetworkTransport.handleReconnection spawns a Task { ... } that schedules continuation.resume(throwing:) after a sleep. The connectionContinuationResumed flag check that protects against double-entry of handleConnectionFailed / handleConnectionCancelled is set BEFORE the inner Task fires. Under macOS 26.4's tightened actor-isolation enforcement, a race appears that the existing flag-based guard does not cover.

Fix that worked for me

Two patches applied together:

1. iMCP fork patch (already in mattt/iMCP#151 discussion)

In App/Controllers/ServerController.swift, configure the server-side NetworkTransport with reconnection disabled (the GUI side accepts connections, so client-style reconnection makes no sense there) and make removeConnection idempotent:

self.transport = NetworkTransport(
    connection: connection,
    logger: nil,
    heartbeatConfig: .init(enabled: false),
    reconnectionConfig: .disabled,
    bufferConfig: .unlimited
)

Plus a removedConnections: Set<UUID> guard in removeConnection to prevent double stop().

2. swift-sdk Sendable fix (Xcode 26 / Swift 6)

A clean rebuild against the Xcode 26 toolchain also fails with two new region-based-isolation errors at NetworkTransport.swift:581 and :812, on sendContinuationResumed / receiveContinuationResumed being captured into Task { @MainActor in ... } closures.

Fix wraps each flag in a fileprivate final class ContinuationResumeFlag: @unchecked Sendable { var value = false } so the reference can cross the actor boundary. Full diff: https://github.com/MySethPorter/iMCP/blob/main/Scripts/swift-sdk-26.4-sendable.patch

Verification

Built with both patches applied, deployed to a 26.4 machine: /mcp connects successfully, no further wrapper-log restart loops. The fork is at https://github.com/MySethPorter/iMCP if you want to look at the actual changes.

Happy to send this as a PR if there's interest, but figured an issue first to discuss the right fix shape (the SDK patch in particular probably belongs upstream at loopwork-ai/swift-sdk, not here).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions