Local peer-messaging inbox socket fails to bind for one of two identical sessions (one-way cross-session messaging)
Version: 2.1.224
Platform: macOS (Darwin 25.6.0), Apple Silicon
Area: cross-session messaging (SendMessage / ListAgents, /tmp/cc-socks peer sockets)
Summary
Two Claude Code CLI sessions launched from terminals on the same Mac, with the same
binary, same flags, and same cwd, 28 seconds apart. One bound a peer-messaging inbox
socket; the other never did. No configuration difference distinguishes them.
The result is a silently one-way channel: session A can message session B, but B cannot
message A. B's sends instead fall through to A's Remote Control bridge registration and
are refused with a message about device-gated bridge sessions — which misattributes the
cause to the bridge and sent us down three rounds of wrong hypotheses.
The two sessions
| | Session A ("Infra Master") | Session B ("Opus Remote") |
|------------------------------------|---------------------------------------|------------------------------------|
| pid / sessionId | 1821 / 58f71b61-20f3-454e-bc48-fe3d665b9e37 | 1967 / 73e341ea-2928-4871-a0a5-6e8b7adca644 |
| launch | claude --dangerously-skip-permissions | claude --dangerously-skip-permissions |
| started (ET; JSON procStart is UTC) | Fri Aug 7 18:00:27 2026 | Fri Aug 7 18:00:55 2026 |
| version / kind / entrypoint | 2.1.224 / interactive / cli | 2.1.224 / interactive / cli |
| cwd | same repo | same repo |
| Remote Control attached | yes (bridgeSessionId present) | yes (bridgeSessionId present) |
| CLAUDE_CODE_MESSAGING_SOCKET | UNSET | /tmp/cc-socks/1967.sock |
| messagingSocketPath in session JSON | absent | present |
| inbox socket on disk | none | bound |
Evidence
~/.claude/sessions/1821.json — note the absent messagingSocketPath:
{"pid":1821,"sessionId":"58f71b61-20f3-454e-bc48-fe3d665b9e37","cwd":"…/Wyckoff Trading App",
"procStart":"Fri Aug 7 22:00:27 2026","version":"2.1.224","peerProtocol":1,
"kind":"interactive","entrypoint":"cli","name":"Infra Master","status":"idle",
"bridgeSessionId":"session_01DLDiVR2gtwwJAFU55UPZDz"}
~/.claude/sessions/1967.json — same shape, plus the socket path:
{"pid":1967,"sessionId":"73e341ea-2928-4871-a0a5-6e8b7adca644","cwd":"…/Wyckoff Trading App",
"procStart":"Fri Aug 7 22:00:55 2026","version":"2.1.224","peerProtocol":1,
"kind":"interactive","entrypoint":"cli","messagingSocketPath":"/tmp/cc-socks/1967.sock",
"name":"Opus Remote","status":"busy",
"bridgeSessionId":"session_01FfXMJ8xLtrpezzpsF1dGqv"}
Socket directory — only one of the two sessions is represented:
$ ls -la /tmp/cc-socks/
drwx------ 3 user wheel 96 Aug 7 18:00 .
srw------- 1 user wheel 0 Aug 7 18:00 1967.sock
Both processes alive throughout:
$ ps -p 1821 -o pid,lstart,command
1821 Fri Aug 7 18:00:27 2026 claude --dangerously-skip-permissions
$ ps -p 1967 -o pid,lstart,command
1967 Fri Aug 7 18:00:55 2026 claude --dangerously-skip-permissions
Env var, measured in each session:
Session A: echo "${CLAUDE_CODE_MESSAGING_SOCKET:-UNSET}" → UNSET
Session B: echo "${CLAUDE_CODE_MESSAGING_SOCKET:-UNSET}" → /tmp/cc-socks/1967.sock
Observed behavior
- A → B: every message delivered, five for five. A dials B's socket successfully.
- B → A: every attempt failed.
ListAgentsin B shows A only as aRemote Controlrow
(never as a local peer), and SendMessage returns:
> 'Infra Master' matches a Remote Control session on this account, and those are
> reply-only from here: messageable only in reply, after it messages you first.
Because A has no inbox socket, its only advertised registration is bridgeSessionId, so
B's send is routed to the device-gated bridge path and refused.
Hypotheses ruled out before the socket was found
- Reply-grant staleness — a reply sent in the same tool round as delivery: still refused.
- Name divergence — A's
from-nameinitially differed from itsListAgentsrow; after
/rename aligned them exactly: still refused.
- Bridge state — disconnect/reconnect of Remote Control on B: still refused. (With B's
bridge off, ListAgents returned "No reachable agents" — A did not appear as a local
peer even with the bridge out of the way, which is consistent with the missing socket.)
- Session class — both are terminal-born local
interactive/clisessions, so the
"bridged session" framing in the error text does not describe the real cause.
Expected vs actual
Expected: every local interactive session binds /tmp/cc-socks/<pid>.sock at startup
and is addressable by name from other local sessions.
Actual: binding silently did not happen for one session. Nothing surfaced the failure —
no warning at startup, no indication in ListAgents, and the eventual SendMessage error
pointed at the bridge instead of the missing inbox.
Suggested fixes
- Fail loudly if the inbox socket does not bind — a startup warning naming the path is
enough; the silence is what made this take an hour to localize.
- Distinguish the two refusal cases in the
SendMessageerror. "Peer has no local
inbox socket (messaging unavailable — try restarting that session)" is actionable;
the current bridge/device-gating text is actively misleading when the peer is local.
- Show socket state in
ListAgentsso a one-way channel is visible before someone
relies on it, rather than after a failed round-trip.
- Investigate the race — the two sessions started 28s apart and
/tmp/cc-socksitself is
timestamped 18:00, so directory creation vs. bind ordering between concurrently
starting sessions is worth checking.
3 Comments
Follow-up with a diagnostic data point: a plain restart of the affected session (quit +
claude --continueto resume the same conversation, same flags, same cwd) re-bound the socket —CLAUDE_CODE_MESSAGING_SOCKETnow set,messagingSocketPathpresent in the session registration JSON, socket file on disk. Full two-way messaging then verified between the two sessions (reply delivered in ~36 s). Since nothing about the session's configuration changed across the restart, this supports the startup-race hypothesis in suggested-fix #4 rather than anything environmental. Also of note for fix #2: during the failure window, theSendMessageerror pointed at Remote Control device-gating, which cost us three falsified hypotheses (reply-grant timing, name divergence via /rename, bridge disconnect/reconnect) before the missing socket was found.Sharper repro hypothesis, from the operator's account of the session sequence plus registration evidence: the failing session was a resume of a conversation that previously had Remote Control attached, launched while that remote re-attached; the session that bound fine 28s later was a fresh conversation (also with a remote). After tonight's fix-restart we also observed stale
bridgeSessionIdcarryover: the restarted session's registration still carried the OLD bridge id while no remote was connected at all; an explicit disconnect/reconnect minted a new id. So the failing conjunction looks like resume + prior bridge state present at startup (bind skipped or lost while the bridge re-attaches), rather than two concurrently-starting sessions racing over the socket directory — consistent with all four sessions we've now observed: fresh+bridge → bound; resume+bridge-at-startup → NOT bound; resume+no-bridge → bound; attach-after-start → stays bound.Final corroborating detail from the operator, tying the stale-state observation to visible symptoms: when connecting Remote Control to the restarted session, the client reported the remote was already connected — it was not (the prior process was gone). An explicit disconnect (which dumped the stale id) followed by reconnect produced a fresh
bridgeSessionIdand everything worked. The operator has also repeatedly seen ghost sessions on the phone after restarting sessions — old entries persisting in the remote session list, even under the same remote name. Both symptoms point the same way: stale bridge state from a closed process is treated as live by both the client and the account-side session list, and a resumed session inheriting that state at startup is the configuration in which the inbox socket fails to bind.