[BUG] Cross-session message written to target transcript but excluded from model's context
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
A cross-session send_message is written into the target session's transcript
(confirmed via list_events) but never enters the assistant's context.
DIRECT PROOF: the target session enumerated the four human-typed turns
surrounding the injected message ("test 3", "open", "run", "?") and skipped
the injected turn sitting directly between "run" and "?" in its own
transcript. Across ~12 attempts it never once echoed an injected code word.
Symptoms:
- send_message returns "Message sent" (no error)
- target wakes: isRunning becomes true
- target then sits with ZERO token consumption (never reaches the model)
- after ~5 minutes a generic "Error" badge appears, no error text on hover
- the same session responds instantly when the user types in it directly
This is a REGRESSION. It worked reliably in the same project days earlier -
sub-chats received injected instructions and returned substantive
multi-paragraph reports. It then stopped with no configuration change.
What Should Happen?
The target session should receive the injected message into its context and
respond to it, as it did days earlier in the same setup.
Error Messages/Logs
=== 1. The tool itself reports SUCCESS. There is no error to paste. ===
Message sent to session local_361fa42c-92d2-46e7-9d81-8396b2bdc81f ("test 4").
Message queued for session local_0468f13d-0faf-4160-becf-1bf7a33e0b8e
("iPro BI"); it will be processed after the in-flight turn finishes if that
session stays healthy.
=== 2. The UI shows a bare "Error" badge with NO text on hover. ===
No stack trace, no message, no code. That is the entire error surface.
=== 3. list_events on the target - the injected turns ARE in the
transcript, with no assistant turn after them ===
Session "test 3" (idle) - showing 16 of 30 messages
[user] test 3
[assistant] Got it - test 3. I'm here and ready. What would you like?
[user] open
[assistant] Not clear what you mean by "open" - a file, a page, a chat?
[user] run
[assistant] I don't have a concrete task to run - the requests "test 3",
"open" and "run" don't specify what exactly.
[user] [user] ?
[assistant] It looks like the last messages ("test 3", "open", "run", "?")
are input tests rather than a clear request.
^^^ THE KEY EVIDENCE: the assistant enumerated the four human turns and
skipped the cross-session turn sitting directly between "run" and "?"
in its own transcript. It was written to disk but not put in context.
=== 4. Also seen, but probably UNRELATED (terminal CLI only; the desktop
app was authenticated and answering typed input normally) ===
20:31:03 [ERROR] API error (attempt 1/11): ... not valid; run /login to
re-authenticate
20:31:03 [ERROR] API auth_error: OAuth refresh token is no longer valid
20:31:03 [ERROR] [engine] turn ended in error
-> failed instantly (api=0ms, 0 tokens), no retry
Note: /login fixed the terminal. Injection still failed afterwards, from a
session created after the fix.
Steps to Reproduce
- Open two Claude Code sessions in the same project directory.
- From session A, call mcp__ccd_session_mgmt__send_message targeting
session B's sessionId with any short message containing a unique code word.
- Tool returns "Message sent to session <id>".
- get_session on B shows isRunning: true, then idle. Zero tokens consumed.
- list_events on B shows the message present in its transcript.
- Type anything into B manually - it answers immediately, but never
references the injected message or its code word.
Claude Model
Not sure / Multiple models
Is this a regression?
Yes, this worked in a previous version
Last Working Version
2.1.227
Claude Code Version
2.1.229 (Claude Code)
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
PowerShell
Additional Information
IMPORTANT TIMING DETAIL - the break does NOT line up with a version update:
- 2.1.227 installed 2026-08-12 11:07
- Injection WORKED on 2026-08-12 (a hub session injected into a sub-chat
and the sub-chat acted on it, confirmed in its transcript)
- Injection BROKE on 2026-08-13 evening - still on 2.1.227
- 2.1.229 installed 2026-08-14 09:29 - AFTER the break
So it regressed WITHIN the same client version. That argues against a
client-side release regression and points to something server-side, or to
accumulated session/project state.
Ruled out by measurement (please don't re-suggest these):
- context size: fails on brand-new empty chats
- burst/load: fails on a single injection
- effort level: fails on both high and medium
- MCP plugins: finance:bigquery / finance:slack disabled - still fails
- app version: full quit + relaunch, and a version update - still fails
- machine resources: 31GB RAM, 13GB free; no hooks defined
- sender session: two different sender sessions, identical failure
- stale session ids in config: corrected - no change
- crossSessionInbound: "accept" in ~/.claude/settings.json, AND a target
session created after that change - still fails
- expired auth: was real but only in the terminal CLI; the desktop app is
authenticated and its sessions answer typed input normally
Additional observation: in older sessions the injected message is not
written to the transcript at all (it vanishes), while in newly created
sessions it IS written but never read. Two distinct behaviours.
Impact: this is the backbone of a 28-chat coordination setup. With it
broken, every instruction must be copy-pasted by hand.
[feedback\[1\].json](https://github.com/user-attachments/files/31139775/feedback.1.json)
3 Comments
Correction: the key evidence block was stripped by GitHub's HTML parsing in
the original report. The injected turn is wrapped in angle brackets, so it
vanished. Re-posting it escaped - this is the verbatim list_events output
from the target session:
[user] run
[assistant] I don't have a concrete task to run - the requests
"test 3", "open" and "run" don't specify what exactly.
[user] {cross-session-message from="local_5ca61699-..."
name="iPro Hub 3" encoded="1"}
Test from Hub 3. Do not read files, do not do any work.
Code word: EREZ-4470
Return one line: the code word + your local time.
{/cross-session-message}
[user] ?
[assistant] It looks like the last messages ("test 3", "open", "run",
"?") are input tests rather than a clear request.
(angle brackets replaced with braces above so it survives rendering)
THE POINT: the cross-session turn sits physically between "run" and "?" in
the target's own transcript. When the assistant ran on "?", it enumerated
its four human-typed neighbours and did not see the turn between them.
S
UPDATE - RESOLVED on engine 2.1.234. Confirming the fix works: after the desktop app updated and its bundled engine moved 2.1.229 -> 2.1.234, cross-session messages are delivered into the recipient's context again. Verified with code-word tests, including a full A -> B -> A round trip between two sessions in the same project.
Two practical notes for anyone still hitting this:
Also ruled out locally before the fix arrived: no hooks, no managed-settings.json, no disable flags in ~/.claude.json, crossSessionInbound=accept - nothing client-config-side caused the 'disabled' state, which supports the original observation that the break happened mid-version (2.1.227, Aug 13) with no local change.
Likely duplicates: #86212, #86671, #86386, #86589.
From my side this can be closed once the team confirms the root cause of the 'read as disabled' state.
The framing in your title — written to the transcript but excluded from the model's context — is the most precise description of this I've seen, and it names the thing that made it expensive to diagnose. The message is genuinely there; it just isn't where the model reads from.
Adding a mechanism detail in case it's useful to whoever fixes it, and a workaround for anyone stuck below 2.1.234.
Why "rendered but not in context" is a distinct failure. When I rebuilt delivery on hooks, I hit the same split from the other side. A
Stophook that writes to stderr and exits 2 keeps the session alive and produces visible output — but the text never reaches the model. Only the stdout JSON ({"decision":"block","reason":"..."}) actually lands in context. Two channels, one of which renders and one of which the model can read, and they are easy to confuse because both "work" from the outside.I don't know whether the underlying bug here is the same shape, but the symptom is identical: something visible to a human, absent to the model.
On @sales172's resolution report: that matches what I've seen reported on #86212, and I'd corroborate the version gate — my Desktop reports nothing to update while its bundled engine is still
2.1.233(visible as"lastVersionBase"in%USERPROFILE%\.claude.json; the About dialog shows the app version, which is a different number).One case that doesn't appear covered by the 2.1.234 fix: a session that is fully idle with no pending turn. The reports describe delivery into a turn in progress or about to start. Waking a genuinely idle session needs
async: true, asyncRewake: true, where exit code 2 starts a turn and delivers stderr as a system reminder.Implementation if useful: https://github.com/msiraga/claude-code-windows-mailbox — PowerShell only, with a self-test, since every result I have is from a single machine.