[BUG] SendMessage returns {"success":true} for messages never delivered; a long-lived session instance goes deaf both ways; stale bridge-pointer leaves host "Connected" with 0 workers (2.1.234)
Amended 2026-08-26. The original report blamed --resume on the sender side. That was wrong; see the correction comment. This body has been rewritten to describe what the evidence actually supports. Two defects are reported.
Defect 1 — SendMessage returns {"success":true} for messages that are never delivered
Cross-session messaging between local Claude Code sessions returns {"success":true} with a msg_id while the message is silently lost. The recipient's transcript never shows an inbound block, and its context never sees the message, including across many subsequent active turns. Nothing is queued or retried; nothing is logged.
The false success is the core problem: agents believe they have communicated. We only caught it by grepping the recipient's transcript for a unique token after every send.
Defect 2 — a long-lived session instance can become unreachable in both directions, with no error surfaced
One session instance (months old, repeatedly restarted, many context compactions, 16 MB transcript) reached a state where:
- it never delivered a message to anyone, ever — always
success, never received; - and nothing could be delivered to it, from any sender, fresh or not;
- while its unix socket was LISTENing and accepting connections, its registry entry was valid, and it otherwise worked normally for interactive use.
No error was surfaced on either side. Only full recreation of the session cured it — killing and restarting the host process was not enough (see "Recovery" below).
Environment
- Claude Code 2.1.234, identical binary across all sessions (
~/.local/share/claude/versions/2.1.234) - Ubuntu 26.04, kernel 7.0.0-30-generic, x86_64
- Long-lived sessions:
claude remote-control --name <n> --spawn=same-dir --permission-mode bypassPermissions, one per project dir, each inside tmux - Registry entries in
~/.claude/sessions/*.jsonall showpeerProtocol: 1,entrypoint: sdk-cli, live pids, validmessagingSocketPath - Note: every remote-control worker runs with
--resume=<sdk-url>, including freshly created ones — the flag is set unconditionally and does not distinguish session age
Evidence matrix
Delivery verified by grepping the recipient's transcript for a unique nonce.
| Sender ↓ / Recipient → | healthy session A | degraded session B | recreated session B′ |
|---|---|---|---|
| fresh headless claude -p | ✅ 4/4, incl. full processing | ❌ | — |
| healthy long-lived session A | — | ❌ | ✅ delivered |
| recreated session B′ | ✅ delivered | — | — |
Every failure has degraded session B as an endpoint; no cell isolates the sender. Historical data point: 50 messages were exchanged successfully between these sessions over two days before B degraded.
Proof-of-delivery standard (useful for anyone reproducing)
Three JSONL entry types appear in the recipient's transcript, and only the last two prove anything:
| entry type | meaning | proof? |
|---|---|---|
| queue-operation | queued (~10 s) | no — appears even when nothing is processed |
| attachment / queued_command carrying the <cross-session-message from-name="…"> block | materialized (~40 s) | yes |
| assistant | processed in a turn | yes |
Grepping too early, or not distinguishing these, produces false conclusions in both directions. A second trap: the nonce also appears in the sender's own transcript (its tool call), which is not evidence of delivery.
Transport layer ruled out
- All peer sockets in
/run/user/<uid>/cc-socks/are LISTENing and held by live processes (ss -xlp), including the failing ones; a rawconnect()to each succeeds, including B's. - Registry
procStartvalues match/proc/<pid>/statfield 22 — no stale identity. - No on-disk queue or spool; messages are lost, not deferred.
- Environment differences (extra CA cert var, node compile cache, inherited shell vars) ruled out: injecting the failing session's environment into a fresh
claude -pstill delivers. - Connection sampler: polling
ss -xtpfor the sender's pid every 250 ms during aSendMessagecall toward B showed the sender never attempting a connection to B's unix socket. Under the revised model this is still unexplained and may be the best lead — it suggests the send path can abandon local delivery before connecting, without surfacing an error, based on some resolved state about the recipient.
Defect 3 (related, likely the same subsystem) — stale bridge-pointer.json ⇒ CCR v2 404 ⇒ host runs with no worker
While recovering from Defect 2 we hit a distinct, reproducible failure:
[17:41:24] Error: CCR v2 worker registration failed for session cse_XXXX: Request failed with status code 404
·✔︎· Connected · system · HEAD
Capacity: 0/32
~/.claude/projects/<slug>/bridge-pointer.jsonkeeps the previoussessionId/environmentId. If the previous session died uncleanly and the server reaped it, worker registration 404s.- The host then stays up advertising
Connectedand a QR/pairing URL, withCapacity: 0/32, zero child worker process, no entry in~/.claude/sessions/, no socket, and absent fromclaude agents --json. It looks healthy from the terminal and is invisible/dead from the apps. - Restarting does not fix it: the new process rewrites
bridge-pointer.jsonupdating onlypid/procStartwhile preserving the stalesessionId/environmentId, so it 404s again. We burned two restart cycles before finding this.
Suggested fixes: don't report Connected when worker registration failed; treat a 404 on registration as a signal to discard the pointer and register a fresh session; surface the condition beyond one startup log line.
Recovery / workaround
- Stop the supervisor, kill the tmux session, confirm no
claude remote-control --name <n>remains. mv bridge-pointer.json bridge-pointer.json.stale-<date>(never delete — you may want the old environment id).- Restart. A new
sessionIdandenvironmentIdare generated, so theclaude.ai/code?environment=…URL changes; the old one points at a dead environment. - This also cured Defect 2 — the recreated instance sends and receives normally.
We now also monitor for Defect 3 automatically: a remote-control host with no child process is the fast, reliable health signal; pgrep on the host process alone proves nothing.
Impact
Multi-session/agent coordination degrades silently to "everyone believes they sent, nobody received", and a session can be dead to the mobile/desktop apps while its terminal says Connected. The misleading success and the misleading Connected cost us most of a day.
Happy to provide sanitized transcripts, registry snapshots, or run instrumented builds.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗