Desktop: Submitted Message Becomes "Queued" and Is Lost or Mishandled

Status Open
Reported on v2.1.251
Maintainer reply None cached
Activity 3 comments · opened Aug 29, 2026
Corrected 2026-08-29. The first version of this report claimed the message was never enqueued and could therefore never fire. That was wrong, and it was built on the wrong session. What the reporter actually observed is below: the message does reach the chip on Enter, it is delivered late, and it arrives behind input typed after it. The measurements have been re-run on the full transcript corpus rather than the 2 percent slice the first version used. Both errors are described at the end.

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 message typed into the composer and submitted with Enter goes to the N message queued chip
instead of the conversation. It then takes a long time to enter the chat flow, and when it does
it lands behind messages typed after it. Submission order and delivery order do not match.

Three things are wrong at once, and the third is the one that costs real work:

  1. The delay is unbounded and unexplained. The chip shows a count and a truncated preview.

It does not say what it is waiting for or how long it has waited.

  1. Delivery is out of order. A message sitting in the chip is overtaken by later input. The

later message gets answered first, in a context that does not yet contain the earlier one.

  1. Waiting and lost are the same picture. Nothing distinguishes a message that will arrive

in ten seconds from one that will not arrive at all, so the only way to find out is to wait
and see whether the instruction was ever acted on.

Out-of-order delivery is worse than plain delay. A queued correction that lands after the work
it was meant to redirect is not merely late. The model acts on the later message first, and the
earlier one then arrives looking like a fresh instruction rather than the correction it was.

Measurements

Sessions record queue activity as first-class transcript events, which makes the normal case
measurable:

{"type":"queue-operation","operation":"enqueue","timestamp":"...","content":"..."}
{"type":"queue-operation","operation":"remove","reason":"absorbed_mid_turn","content":"..."}

Normal absorption is fast. Two sessions, same app instance, same minute, both mid-turn:

20:30:19.091  enqueue  "You should be adding a table at the end of every cycle"
20:30:19.130  remove   absorbed_mid_turn        <-  39 ms
20:30:32.755  enqueue  "You should be adding a table at the end of each cycle"
20:30:32.775  remove   absorbed_mid_turn        <-  20 ms

But latency in the same app across the same few minutes spans three orders of magnitude:

20 ms   plain typed message
39 ms   plain typed message
27 s    batch of 13 cross-session messages
34 s    batch of 2 cross-session messages

There is no single expected wait a user could learn. The chip in this report stayed up far
longer than any of these, through more than eight minutes in which the session worked normally,
opened two pull requests, and produced more than fifty assistant turn boundaries.

What I could not confirm from logs is the eventual delivery. Searching the full local corpus
for two verbatim fragments of the chip's own preview text returns nothing:

corpus: 16,384 transcripts across 6 profile directories, recursive, no sampling
  "do you know what I mean"   -> 0 files
  "why are you not doing it"  -> 0 files
  "end of each cycle"         -> 4 files   <- CONTROL, proves the probe fires

The control matters. A probe that returns zero everywhere is indistinguishable from a broken
probe, so the third pattern is one that must fire, and does. The reporter watched the message
enter the conversation eventually. I am reporting that I could not corroborate that from the
transcripts, not that it failed to happen.

What Should Happen?

  1. Delivery order should match submission order. A message queued first should be delivered

first, ahead of anything typed after it.

  1. The chip should say what it is waiting for and how long it has waited.
  2. There should be a way to deliver the message now rather than waiting an unbounded time.
  3. If a queued message cannot be delivered, that should surface rather than leaving a chip that

implies it is safely waiting.

Error Messages/Logs

No desktop log is available, which is worth reporting on its own. The Windows MSIX build at this
version writes none I can find:

  • %APPDATA%\Claude\logs\main*.log exists, nothing written since 2026-08-28.
  • %LOCALAPPDATA%\Claude\Logs\main.log likewise.
  • No log of any type newer than 2026-08-28 anywhere under %LOCALAPPDATA%\Packages\Claude_pzs8sxrjxfjjc\.

Older rotated logs do contain [LocalSessionManager] flushed held steers and
cancelQueuedMessage ... -> cancelled, so this logging exists and is not landing for this
build. Without it a user cannot see which queue holds a waiting message, or why it is waiting.

Steps to Reproduce

No deterministic repro, and I would rather say so than invent one. The conditions:

  1. Twelve local desktop sessions open in one app instance, each in its own git worktree of the

same repository, several of them exchanging cross-session messages.

  1. The target session was mid-turn, making continuous tool calls, and had already absorbed

several queued inputs during that same turn in tens of milliseconds.

  1. A plain sentence was typed and submitted with Enter. No slash command, no ! prefix, no

session switch.

  1. It went to the chip, stayed a long time, and arrived behind messages typed after it.

The cross-session message traffic may be a factor. Those batches are the only inputs measured
here that took tens of seconds rather than milliseconds, and the affected session was receiving
them throughout.

Claude Code Version

Bundled CLI 2.1.251, desktop app 1.37937.0 (MSIX Claude_1.37937.0.0_x64__pzs8sxrjxfjjc)

Platform

Claude Desktop app

Operating System

Windows 11 Pro, build 10.0.26200

Additional Information

Related, none of them this report:

  • #73661 asks for queued messages to be processed sequentially, one message per turn, FIFO.

That request and this bug are the same underlying complaint about ordering.

  • #87037 asks for the ordering rule to be documented, noting that plain prompts fold into the

running turn. This was a plain prompt that did not fold in, while an almost identical one in a
sibling session did, 13 seconds earlier.

  • #73118 covers long turns blocking queued messages. Adjacent, but does not cover order.
  • #81582 covers the chip becoming undismissable when cancelQueuedMessage falls through every

strategy because the uuid "exists in none of the manager's queues". Possibly the same desync
seen from the cancel side.

  • #77010 and #77451 cover queued messages lost across a session switch. No switch here.

On the two errors in the first version of this report, since both are the kind that survive
review by looking measured:

The first was scope. I searched 321 transcripts and reported a zero. The real corpus is 16,384
across six profile directories, so I had covered about two percent of it while presenting the
result as a corpus-wide census.

The second was attribution. I read the queue events of the wrong session, found the message
absent, and concluded it had never been enqueued anywhere. It had been enqueued in a different
session and absorbed in 20 milliseconds. A zero from the wrong file reads exactly like a zero
from the right one.

View original on GitHub ↗

3 Comments

wshallwshall · 1 day ago

Correction: I have rewritten this issue. The original version was wrong on its central claim.

It said the message was never enqueued and could therefore never fire. Two mistakes produced that:

  1. Wrong session. I read the queue events of a sibling session, found the message absent, and

generalized. It had in fact been enqueued in a different session and absorbed in 20 milliseconds.

  1. Wrong corpus. I searched 321 transcripts and reported the zero as a corpus-wide census. The

real corpus is 16,384 transcripts across six profile directories, so I had covered about two
percent of it.

The actual behavior, from the reporter: the message goes to the chip on Enter, takes a long time to
enter the chat flow, and lands behind messages typed after it. That makes this an ordering and
latency bug, not a loss bug. The title and body now say so.

Leaving the record of both errors in the issue rather than quietly editing them out, since a zero
from the wrong file reads exactly like a zero from the right one, and that is worth flagging to
anyone who reads the measurements here.

One consequence for triage: my earlier suggestion that this explains #81582 no longer follows. It
may still be related, but the evidence I offered for it does not support the link.

wshallwshall · 1 day ago

Here is an image of a stuck queued message

<img width="762" height="136" alt="Image" src="https://github.com/user-attachments/assets/828db4f9-06ac-4bca-98a4-076aee595163" />

wshallwshall · 1 day ago
Corrected. The first version of this comment said "delivery took 10 ms". That number is the queue's own bookkeeping latency, not delivery to the model, and it was wrong by three orders of magnitude on the one figure a reader would quote. It also called the defect cosmetic, which understates a measured cost. Both are fixed below and the errors are described at the end.

Same bar, a different failure: the queue emptied, the chip kept advertising, and I re-uploaded

Environment: claude-desktop, version 2.1.246, Windows 11.

I put an image (no text) into the composer and hit Enter while a turn was running. It was delivered. The chip went on showing 1 message queued [Image] for the next five minutes, so I assumed it was stuck and submitted the same image again.

Timeline

| Time (UTC) | Record | Detail |
|---|---|---|
| 23:49:10.340 | queue-operation enqueue | no content key |
| 23:49:10.340 | attachment queued_command | prompt: [{"type":"image"}], origin.kind: "human", source_uuid: 52fdad7d-... |
| 23:49:10.350 | queue-operation remove, reason: absorbed_mid_turn | queue released it, 10 ms after Enter |
| 23:49:22.986 | next API request | the image enters the model's context here, 12.6 s after release |
| 23:50:00.281 | a later message | submitted and delivered normally, while the chip still showed 1 queued |
| 23:53:59.102 | enqueue | I gave up and resubmitted the same image |
| 23:54:14.621 | user turn | resubmitted copy lands, 15.5 s later. Chip finally clears |

The two copies are byte-identical: sha256 ba4cb9281d6c1e7d..., 319,353 bytes, PNG 1782x1509.

The model demonstrably received the first copy. At 23:53:56.942, seventeen seconds before the second copy arrived, it quoted three exact figures off the image and correctly placed a block at the bottom of it. Those figures appear nowhere else in the transcript, in no tool result and no file read.

The queue was never slow. Only the indicator was wrong.

I FIFO-matched every queue-operation record in the session. Zero unmatched removals, final depth zero, depth never above 2.

| Window | Duration |
|---|---|
| Longest hold by any queue entry, anywhere in the session | 41.3 s |
| Chip advertising a queued message while the queue was provably empty | 4 min 48.8 s |
| Total time a false or duplicate queue indicator was on screen | 5 min 4.3 s |

Nothing was lost, delayed in the queue, or dropped. The badge and the queue simply came apart, and that gap is the bug.

The mechanism the records point to

Queue audit records carry no identifier. Across 323 transcripts and 33,734 queue-operation records there are exactly four key sets, and the union of every key ever present is:

content, operation, reason, sessionId, timestamp, type

No id, no uuid, no sequence number. The payload does have an identity, since the queued_command attachment carries source_uuid. That id is absent from every queue event.

So content, the message text, is the only thing that can name a particular queued item:

| Operation | Count | Carries content |
|---|---|---|
| dequeue | 12,416 | 0 of 12,416. Positional, pops the head. |
| remove | 4,445 | 4,294 of 4,445. Content-addressed, names the item by its text. |

An image-only submission enqueues with no content key at all, 431 of 16,873. In this session the correspondence is exact in both directions: 3 of 3 image enqueues carry no content key, 21 of 21 text enqueues do.

The collision is a content-addressed remove of an item with no content to address it by:

remove, has_content=True,  reason=(none)             3875
remove, has_content=True,  reason=absorbed_mid_turn   419
remove, has_content=False, reason=(none)              138
remove, has_content=False, reason=absorbed_mid_turn    13   <-- this bug

Thirteen occurrences, across 8 sessions and 2 days, in one user's corpus.

That last step is an inference and I am labelling it as one. A transcript holds no renderer state, so the correlation is complete but it is not the mechanism. Whoever fixes this needs the client code. What is measured is that the queue events give the UI nothing to match an image removal against.

What it cost, since "only the indicator is wrong" was my own understatement

The defect is confined to the indicator. The consequence is not.

  • A 319 KB image was uploaded and tokenized twice for one delivery.
  • Five minutes of wall clock, of which 4 min 48.8 s was spent waiting on an indicator that was lying.
  • A four-minute debugging detour: 11 API responses and 43,804 fresh input tokens spent working out whether a message had been lost.
  • The chip is no longer usable as a signal. Its label for an image is [Image] whether the queue is real or stale, so there is no way to tell the two apart from the UI. That is why I waited, and then why I re-sent.

Suggestions

  1. Put a stable id on enqueue, dequeue and remove, and have the UI retire entries by id. That removes the whole class rather than the image case alone.
  2. Failing that, give a content-less enqueue a placeholder content value so the existing content match has something to match on.
  3. Independently of either, the chip should say how long it has waited. A queued message and a phantom one currently render identically.

What the first version got wrong

  • "Delivery took 10 ms." That is enqueue to remove, the queue releasing the item. Entry into the model's context happens at the next API request, 12.6 s later. Worth stating because the two are easy to conflate and the transcript makes only the first one obvious.
  • "Only the indicator is wrong." True of the defect, misleading about the impact, and the impact is the reason to fix it.
  • How the bad number got published. It originated in my own earlier analysis inside the same session, and I then cited that analysis as the authority for the public comment without re-deriving it. A self-citation loop. The correction came from re-reading the raw records and decoding the PNG, which is what I should have done first.