User turn silently dropped: message is enqueued, dequeued 1ms later, and never dispatched (v2.1.220, VS Code extension)
Summary
A user message is accepted by the CLI, removed from the prompt queue, and then never
produces an inference request. No user entry is written to the transcript, no[API REQUEST] source=sdk is issued, and the session sits in the "running" state
indefinitely. The CLI process stays alive and remains responsive to other requests on
the same channel — it simply never runs the turn.
Esc / interrupt has no effect, because there is no in-flight turn to interrupt. The only
recovery is to abandon the channel (new tab + /resume, or kill the CLI process).
This is not rare: 22 of 288 session transcripts on this machine (7.6%) end with the
signature, spanning 2026-07-04 through 2026-07-30 across six different project
directories.
Environment
- Claude Code VS Code extension v2.1.220 (
anthropic.claude-code-2.1.220-darwin-arm64) - macOS 15 (Darwin 25.5.0), arm64
- Build hashes observed across windows in a single VS Code launch:
cc_version=2.1.220.3fc, .5f8, .6cb, .8d4, .b3f, .b7d
- Every affected process is spawned by the extension with:
--output-format stream-json --verbose --input-format stream-json
--max-thinking-tokens 31999 --permission-prompt-tool stdio
--resume=<session-id> --setting-sources=user,project,local
--permission-mode auto --include-partial-messages
--debug --debug-to-stderr --enable-auth-status --no-chrome
--replay-user-messages
The signature
In the session transcript (~/.claude/projects/<project>/<session-id>.jsonl), a healthy
turn looks like this — the dequeue is immediately followed by the user entry:
{"type":"queue-operation","operation":"enqueue","timestamp":"2026-07-09T04:13:26.xxxZ"}
{"type":"queue-operation","operation":"dequeue","timestamp":"2026-07-09T04:13:26.xxxZ"}
{"type":"user","message":{"role":"user","content":[...]}}
A dropped turn looks like this — and the file ends there:
{"type":"queue-operation","operation":"enqueue","timestamp":"2026-07-31T02:15:21.852Z"}
{"type":"queue-operation","operation":"dequeue","timestamp":"2026-07-31T02:15:21.853Z"}
<EOF>
The message leaves the prompt queue and disappears. Because the turn is never created,
nothing is ever appended — which is also why the conversation appears to have "lost" the
message entirely in the UI.
Occurrence A — after /compact (clearest trace)
Session e8b6a198, channel mcuzlb3xip, extension host log
(~/Library/Application Support/Code/logs/<ts>/window1/exthost/Anthropic.claude-code/Claude VSCode.log):
22:13:22.586 Received message from webview: io_message channelId=mcuzlb3xip "/compact"
22:13:22.620 Dynamic tool loading: found 4 discovered tools (3 carried from compact boundary)
22:13:22.633 [API:timing] dispatching to firstParty model=claude-opus-5
22:13:22.636 [API REQUEST] /v1/messages x-client-request-id=aa5d520d-... source=compact
22:13:25.465 Stream started - received first chunk / first byte after 2833ms
22:14:57.157 Forked agent [reactive-compact] finished: 1 messages,
input=5704 output=8001 cacheRead=20636 cacheCreate=139461
22:14:57.189 [API REQUEST] /v1/messages/count_tokens (x4)
22:14:57.895 Hook SessionStart:compact (SessionStart) success
22:15:21.851 Received message from webview: io_message channelId=mcuzlb3xip
{"role":"user","content":[{"type":"text","text":"Continue doing what you were doing"}]}
22:15:21.862 LSP Diagnostics: getLSPDiagnosticAttachments called
22:15:21.862 LSP Diagnostics: Checking registry - 0 pending
22:15:21.862 Hooks: Found 0 total hooks in registry
22:15:21.863 Hooks: checkForNewResponses returning 0 responses
─── nothing further ───
22:15:29.079 [skills] active — switching poll interval to 2000ms
22:16:29.087 [skills] idle — switching poll interval to 30000ms
22:17:02.997 Received message from webview: {"type":"request","channelId":"mcuzlb3xip",
"request":{"type":"get_usage"}}
22:17:03.005 fetchUtilization: GET /api/oauth/usage (attempt 1)
22:17:03.366 fetchUtilization: 200 after 1 attempt(s)
Turn preparation begins (LSP attachment collection, hook registry check) and then stops.
The two lines that always precede a real turn — Dynamic tool loading: found N discovered and
tools[API:timing] dispatching to firstParty — never appear.
Every [API REQUEST] source in that window's entire log:
1 source=compact
4 source=count_tokens
1 source=growthbook
No source=sdk. The main inference request was never issued.
Occurrence B — first message of a brand-new session
Session 6bd0de7f, channel p4558d7rd6r, ~3 hours earlier on the same machine:
19:28:02.994 launch_claude channelId=p4558d7rd6r cwd=<project> permissionMode=auto
19:28:08.976 log_event time_to_interactive ttiMs=6013
19:28:12.388 io_message channelId=p4558d7rd6r (user's first message, with an image attachment)
19:28:12.389 request generate_session_title channelId=p4558d7rd6r
19:28:12.398 act_dont_rederive_arm_active source=growthbook
19:28:12.661 [API:timing] dispatching to firstParty model=claude-haiku-4-5-20251001
19:28:12.662 [API REQUEST] /v1/messages x-client-request-id=63176a20-bd32-461f-b022-951b9161e9ca
source=generate_session_title
19:28:13.534 Stream started - first byte after 874ms
19:28:13.637 rename_session ← tab title updates, so the UI looks alive
─── 16 minutes: zero webview messages, zero API requests ───
19:44:10.870 io_message on a NEW channel jcvwzmmawa
19:44:11.076 [API REQUEST] source=sdk model=claude-opus-5 x-client-request-id=a529e047-...
19:44:12.325 first byte after 1250ms ← dispatches normally in ~200ms on the new channel
19:44:16.610 interrupt_claude on OLD channel p4558d7rd6r (x4 within 0.8s, no effect)
Only the Haiku title-generation call fired. The source=sdk conversation request never
existed for that channel. The four interrupts landed on a channel with no live turn.
Frequency
Final-entry type across all 288 session transcripts in ~/.claude/projects
(transcripts on this machine begin 2026-06-30, so this is effectively full history):
205 last-prompt ← normal end
28 ai-title
27 mode
23 queue-dequeue ← this bug
2 user
1 queue-enqueue
1 file-history-snapshot
1 assistant
All 23 have an enqueue immediately prior, 0–6 ms before, with nothing after:
| timestamp (UTC) | session | enqueue→dequeue | transcript lines | compact nearby |
|---|---|---|---|---|
| 2026-07-04T02:51:46 | 7caa8920 | 0 ms | 799 | |
| 2026-07-04T16:08:56 | bd838c0b | 1 ms | 608 | |
| 2026-07-05T03:58:03 | 19336ffd | 1 ms | 979 | yes |
| 2026-07-05T14:56:57 | a0c9ab5c | 1 ms | 158 | |
| 2026-07-06T03:10:09 | 700f6dbe | 0 ms | 254 | |
| 2026-07-06T14:43:23 | c2ce4b66 | 0 ms | 119 | yes |
| 2026-07-06T16:40:38 | 492d2122 | 1 ms | 130 | |
| 2026-07-06T17:03:37 | 26f26e52 | 0 ms | 243 | yes |
| 2026-07-08T19:56:39 | 4086d727 | 0 ms | 132 | |
| 2026-07-09T02:03:59 | ba5c8c30 | 0 ms | 312 | |
| 2026-07-09T04:19:42 | 5250e97e | 0 ms | 17 | |
| 2026-07-11T00:19:24 | dd214f3d | 1 ms | 850 | |
| 2026-07-12T03:05:13 | 424edb99 | 1 ms | 308 | |
| 2026-07-12T03:29:15 | e6363c85 | 0 ms | 308 | |
| 2026-07-12T17:42:59 | ae0d8ed6 | 0 ms | 348 | |
| 2026-07-13T04:15:47 | 4da2e7f3 | 6 ms | 653 | |
| 2026-07-22T21:10:04 | 3c7eae51 | 1 ms | 265 | |
| 2026-07-24T04:24:24 | 5709089b | 0 ms | 17 | |
| 2026-07-26T23:27:14 | 523c3d41 | 4 ms | 70 | |
| 2026-07-29T22:39:38 | 135450d5 | 2 ms | 856 | (same session id appears |
| 2026-07-29T22:39:38 | 135450d5 | 2 ms | 856 | under two project dirs) |
| 2026-07-30T01:22:37 | 0a376432 | 0 ms | 335 | |
| 2026-07-31T02:15:21 | e8b6a198 | 1 ms | 1736 | yes |
22 unique sessions / 288 = 7.6%, across six project directories, over roughly four
weeks and multiple releases.
Anyone can check their own machine with:
for f in ~/.claude/projects/*/*.jsonl; do
tail -1 "$f" | grep -q '"operation":"dequeue"' && echo "$f"
done
A control case inside a single transcript
Session 5250e97e contains both a healthy and an orphaned dequeue, six minutes apart:
04:13:26 queue-enqueue
04:13:26 queue-dequeue
04:13:26 user ← healthy: dequeue produces a user entry
04:13:26 attachment x4
ai-title
04:13:37 assistant
04:13:43 assistant ← turn completes normally
04:19:42 queue-enqueue
04:19:42 queue-dequeue ← orphaned: nothing follows, ever
5709089b is identical in shape, and there the preceding turn had already written itslast-prompt and ai-title markers before the next message vanished. The session is
fully initialized and healthy when the drop occurs.
What this rules out
- Not the IPC transport. The same channel serviced a
get_usagerequest 100 s after
the stall and answered in 360 ms.
- Not the network or auth. The immediately preceding compact request got first byte in
2833 ms; in occurrence B, all post-recovery requests had first byte 900–1900 ms.
- Not a hung process. PID 43009 had consumed 8.7 s of CPU across 8.5 minutes of wall
clock — idle, not spinning. 19 threads, no pending network connections.
- Not context size. Affected transcripts range from 17 to 1736 lines.
- Not
/compact. Only 4 of 23 occurrences have a compact anywhere nearby. - Not user hooks. In occurrence A the
SessionStart:compacthook completed
successfully at 22:14:57.895 and the registry reported 0 pending hooks. (This machine
does run custom SessionStart / PreToolUse / PostToolBatch hooks; all of them
returned status 0 in every affected trace, and 18 of the 23 occurrences have no hook
activity in the preceding turn at all.)
- Not session startup ordering. Per the control case above, the drop can happen on the
second or later turn of a session that has already completed turns normally.
Possible common factor
In both fully traced occurrences, the dropped turn is the first user message after a
session-state transition during which a non-sdk inference ran on that session:
| | transition | concurrent non-sdk call | outcome |
|---|---|---|---|
| Occurrence B | session creation | generate_session_title (haiku, 874 ms) | turn never dispatched |
| Occurrence A | /compact | forked reactive-compact agent (opus) | turn dequeued into the void |
This is suggestive rather than conclusive — the 23-case dataset shows the drop also
happens on ordinary turns, so if there is a single race it is probably in the
queue-drain/turn-start handoff generally, with these transitions widening the window.
Impact
The session is unrecoverable in place. The UI shows a spinner indefinitely; the composer
switches to "Queue another message", so anything typed afterward queues behind a turn
that will never complete. Interrupting does nothing. Users generally cannot tell this from
a slow model response, so the usual reaction is to wait several minutes before restarting.
Workaround
Open a new tab and /resume the session — the transcript on disk is intact up to the
dropped message. Killing the CLI process also works; the extension relaunches it.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗