Dispatch session collisions cause message loss and transport failures
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
- Open a Cowork/Dispatch session with several child tasks spawned.
- Send follow-up messages in the Dispatch thread while child sessions are active.
- 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:
- Prevents any single transport from staying connected long enough to relay messages.
- Can trigger
deleteBridgeSessionwhich wipes the local parent and all its OAuth state, causing a cascade of re-authentication and further transport failures. - Leaves
pendingTurnsin 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 cachewhich 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).
This issue has 13 comments on GitHub. Read the full discussion on GitHub ↗