Dispatch session collisions cause message loss and transport failures

Resolved 💬 13 comments Opened Mar 28, 2026 by jkdavies Closed May 7, 2026

Bug: Dispatch session collisions cause message loss and transport failures

Environment

  • App: Claude Desktop (macOS)
  • Date observed: 2026-03-27
  • Log source: ~/Library/Logs/Claude/main.log

Summary

When using Dispatch mode (Cowork), the sessions-bridge encounters repeated session collisions where multiple cloud session IDs (CSEs) attempt to bind to the same local Dispatch parent session. This creates a rapid displacement loop that prevents messages from being delivered, causes transport initialization failures, and results in user messages being silently dropped or routed incorrectly.

The user-visible symptom is that replies typed into a Dispatch thread are either lost entirely or "passed off" into a different Copilot chat session that then fails to respond.

Reproduction

  1. Open a Cowork/Dispatch session with several child tasks spawned.
  2. Send follow-up messages in the Dispatch thread while child sessions are active.
  3. Observe that the reply either never arrives or surfaces in the wrong session context.

Exact trigger conditions are unclear, but the collision loop began immediately after a prior session query completed with isError=true.

Error Details

1. Session collision loop (11 collisions in ~2 minutes)

Starting at 17:03:58, pairs of CSE sessions repeatedly displace each other on the same local parent (local_ditto_6cf1aa12-...):

[error] [sessions-bridge] Session collision: cse_016UUj8Mj7XJAUsMEAWAw5hW is displacing cse_01DPeFSKvZkbvD3heTsfDWzN (both bound to local_ditto_6cf1aa12-..., displaced pendingTurns=0)
[error] [sessions-bridge] Session collision: cse_01DPeFSKvZkbvD3heTsfDWzN is displacing cse_016UUj8Mj7XJAUsMEAWAw5hW (both bound to local_ditto_6cf1aa12-..., displaced pendingTurns=0)

This pattern repeated with at least 6 different CSE IDs cycling against each other (cse_01DPeF..., cse_016UUj..., cse_01NLWFp..., cse_015zc5..., cse_01Dbz..., cse_01Qtic...).

2. Transport initialization failure during collision

A collision triggered a deleteBridgeSession which wiped the local parent while a new CSE transport was still attaching:

[warn] [sessions-bridge] Failed to post final result for cse_01DPeFSKvZkbvD3heTsfDWzN; server DELETE may 409: write() before transport initialized
[error] [sessions-bridge] Failed to connect transport for session cse_01DPeFSKvZkbvD3heTsfDWzN: transport closed during attachBridgeSession

The sequence was: collision detected -> deleteBridgeSession wipes local parent -> OAuth cache cleared -> fresh OAuth exchange started -> but transport was already closed -> attachBridgeSession fails.

3. Stale pendingTurns

Throughout the session, there are recurring warnings about stale pending turns suggesting the bridge loses track of in-flight work:

[warn] [sessions-bridge] Stale pendingTurns detected for session cse_01A2W7aptb5XBXZXwLsrc7Bx (pendingTurns=2), resetting counter and keeping transport open
[warn] [sessions-bridge] Stale pendingTurns detected for session cse_01PJkqGu6XntvdWGT7r4uG2v (pendingTurns=1), resetting counter and reconnecting transport

4. User-reported symptoms in-log

The logs capture the user's own messages describing the failure:

  • 17:25:31 — "Something is going on with your messaging system in dispatch mode. Your replies are being sent via s..."
  • 18:15:21 — "You're having problems responding in this dispatch thread. I can see you kicked off a claude code se..."
  • 18:21:07 — "I'm typing in a dispatch thread, but its literally just passing it off into a copilot chat and faili..."

Root Cause Hypothesis

The sessions-bridge poll API is returning duplicate or recycled work items for the same local Dispatch parent. When a new CSE arrives while an existing CSE is already bound, the bridge displaces the old one. But the displaced session re-appears in the next poll cycle, creating a ping-pong loop. This loop:

  1. Prevents any single transport from staying connected long enough to relay messages.
  2. Can trigger deleteBridgeSession which wipes the local parent and all its OAuth state, causing a cascade of re-authentication and further transport failures.
  3. Leaves pendingTurns in a stale state so the bridge doesn't know whether work completed.

A possible contributing factor is the isError=true completion at 17:03:33 on the prior session (cse_01A2W7apt...), which may have left the server-side session in an ambiguous state that caused it to re-dispatch work.

Expected Behavior

  • Only one CSE should be bound to a local Dispatch parent at a time.
  • If the server issues a new CSE for the same parent, the old CSE should be cleanly retired (not re-polled).
  • User messages sent during Dispatch should be reliably routed to the active session and never dropped.

Actual Behavior

  • Multiple CSEs fight over the same local parent in a collision loop.
  • The transport is destroyed and re-created repeatedly, sometimes failing to initialize.
  • User messages are lost or misrouted to the wrong session type.

Suggested Investigation Areas

  • sessions-bridge poll deduplication: Why does the poll API return work for sessions that were just displaced? Is there a missing acknowledgment or session-state fence?
  • deleteBridgeSession race condition: The wipe-and-recreate path during a collision doesn't appear to guard against concurrent transport attachment.
  • OAuth cache invalidation during collision: The collision path calls clearing token cache which forces a fresh exchange; under rapid collision this could amplify latency and failure rates.
  • Stale pendingTurns recovery: The "reset counter" path doesn't appear to notify the server, potentially causing the server to re-dispatch the same work.

Log File

Full logs available at ~/Library/Logs/Claude/main.log on the reporter's machine. Key line ranges: 15972–16296 (collision loop), 18170–18200 (user complaint context).

View original on GitHub ↗

This issue has 13 comments on GitHub. Read the full discussion on GitHub ↗