User turn silently dropped: message is enqueued, dequeued 1ms later, and never dispatched (v2.1.220, VS Code extension)

Status Fixed / completed
Reported on v2.1.220
Maintainer reply None cached
Activity 1 comment · opened Jul 31, 2026 · closed Aug 1, 2026

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
tools
and [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 its
last-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_usage request 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:compact hook 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.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗