send_message (cross-session) never delivers and leaves the target session hung on an empty turn
Summary
mcp__ccd_session_mgmt__send_message (session → session) returns success, renders the message in the target session's UI, and puts that session into a running state — but no turn is ever created. The target spins indefinitely and has to be cancelled with Esc. The target's model never receives the message.
The failure is silent at both ends: the sender gets Message sent to session … ("<title>"), and the recipient looks busy.
Environment
- Claude Code 2.1.227, desktop app
- Windows 11 Pro 26200
Reproduction
- Open two sessions, A and B.
- From A, call
send_messagetargeting B, with a unique token in the body. - Observe B: the message text renders and the working indicator starts.
- Wait. B produces no output and stays "working" indefinitely (2+ minutes observed).
- Press Esc in B to recover. B returns to a normal prompt undamaged.
Expected: the message arrives in B as a user turn and B acts on it.
Actual: B renders the text, enters a working state, produces nothing, writes nothing, and hangs until interrupted.
Evidence
Checked against the transcript files at ~/.claude/projects/<slug>/<sessionId>.jsonl:
- The unique token appears 2× in the sender's transcript (the tool call and its result) and 0× in the recipient's.
- The recipient's transcript is byte-identical before and after the send (93,037 bytes), including after the Esc — the aborted turn leaves no record at all.
- The recipient's process showed ~6s cumulative CPU while displaying "working" — blocked, not computing.
- Scanning all 476 transcript files on this machine, the only
origin.kindvalues that have ever existed are:
| origin.kind | count | source |
|---|---|---|
| human | 13,158 | user input |
| task-notification | 965 | background task completion |
| coordinator | 9 | parent → subagent (isSidechain: true, has agentId) |
There is no record kind for a cross-session message. Not one instance, across every session ever run on this machine.
This suggests the wake/notify half of the receive path is wired but the turn-creation half is not, so the recipient is started on a prompt that never materialises.
Impact
Pointing this at a session that is doing real work stalls it until a human notices the spinner and cancels. Because both ends report success and no error surfaces anywhere, there is nothing to indicate the message was lost or that the target is now stuck.
Note
coordinator → subagent messaging (the Agent tool + SendMessage, within a single session) works correctly. Only session → session is affected.
Showing cached comments. Read the full discussion on GitHub ↗
3 Comments
Hung empty turn after a "successful" send — #86298 documents the same failure chain with root-cause analysis (Windows desktop, regression at app 1.28929.0 / bundled CLI 2.1.227, still present on app 1.30096.1.0 / CLI 2.1.229): the desktop bridge sends the message with a class-less
origin:{kind:'peer'}, the recipient CLI/SDK's cross-session consent gate holds it for an approval no desktop surface offers, anddialogExpiry(~5 min) then drops it — while the sender keeps a success receipt. A memory-dump repro in that thread shows the payload reaching the recipient CLI process but never its transcript. SettingcrossSessionInbound: "accept"in user settings does not unblock it (tested on running, cold-started, and post-restart fresh sessions).Also reproducible on macOS — this is cross-platform, and on this machine it is a regression that landed between Aug 10 and Aug 14. (Both this issue and #86603 are labeled
platform:windows; macOS is affected too.)Environment: Claude Code 2.1.228, desktop app, macOS 26.5.2 (arm64).
Today's failures, all silent-success at the sender:
Message sent to session …; the target's UI andlist_eventsrendered the message at the end of its transcript; the target's~/.claude/projects/<slug>/<uuid>.jsonlnever received it (0 hits for the body, noqueue-operationrecord). On one send the target visibly woke —lastActivityAtadvanced and it showed "running" for ~14 minutes — but its transcript grew by zero events, matching the wake-without-turn behavior described here.DELIVERY_PROBE_1786712444): the marker appears only in the sender's own transcript (tool_use + tool_result records). Target jsonl: 0 hits. A full binary scan of~/Library/Application Support/Claude(UTF-8 and UTF-16LE patterns) finds the marker nowhere on disk — the rendered message exists only in app memory/cloud state.claude --resumeand asking it to check its input history: it confirms the marker never appeared in any turn it received. 4/4 lost, both directions.Two data points that may help triage:
{"type":"queue-operation","operation":"enqueue",…}carrying the<cross-session-message …>envelope in plaintext, immediately followed by the same content as auserrecord. In today's failures that enqueue record is simply never written, while the wake still happens — consistent with #86603's finding that the notify half survives and the enqueue/persist half fails. The window also lines up with #86603's "worked on this machine until 2026-08-11" on Windows.list_events(the ccd_session_mgmt MCP read tool) renders the lost message at the end of the target's transcript, so a sender that double-checks "did it arrive?" sees it there and reasonably concludes delivery succeeded. Cross-session orchestration (supervision / handoff flows) fails silently at both ends: sender sees success plus the rendered message, target sees nothing, and no error surfaces anywhere.Workarounds we have adopted: treat
send_messageas a UI notice only; anything the target must actually receive goes throughclaude --resume <target-cli-session-id>(message-as-turn-input, 100% arrival) or a durable file both sides read.Same failure on Windows 11, desktop app, 2.1.229 — with one difference from your title that may matter for diagnosis.
The target session did not hang. It carried on completely normally after both sends: no spinner, no empty turn, nothing to cancel. It ran 60+ further turns on real user input and finished a long workflow cleanly. As far as it was concerned the messages never existed.
So the silent drop occurs without the hang. Those look like separable failures rather than one, which would also explain why #86059 and #86386 describe the recipient stopping or spinning while this case shows neither.
A second success-shaped return. You quote
Message sent to session … ("<title>"), which is what I got when the target was idle. There is another when the target has a turn in flight:Also never delivered. That one is at least conditional, but the condition is unfalsifiable from the sender's side — and the target here demonstrably stayed healthy.
Evidence, using your method
Two messages A → B, ~6 min apart, each with a unique token.
grep -con the on-disk transcripts:| token | sender | recipient |
|---|---|---|
| A | 6 | 0 |
| B | 6 | 0 |
|
cross-session-message| — | 0 |Recipient identity confirmed independently before counting; 2,238,259 bytes and actively written throughout, so this is not a stalled or wrong file.
Neither did
list_eventsorsearch_session_transcriptsshow them — I verified the latter does index that session by first searching a string I knew was in it. (Note the macOS report #86370 states the message is visible vialist_eventsthere; on Windows it was not, though I paged ~70 of 977 events rather than all.)Detection, not a workaround
There is no way to make the message arrive. The only option is to notice it didn't: after sending, search
search_session_transcriptsfor a distinctive string from the body, and treat the return value as carrying no information either way.