DeepSeek Harness duplicate user bubble: queued echo and log

TroubleshootingPublished 2026-10-30Author: DeepSeek Plugin Market
DeepSeek HarnessDSHmessage bubblequeuesession-controllerfrontend rendering
One message shows two identical user bubbles with the same timestamp in DeepSeek Harness: the queued echo and the persisted message render twice.

"Ready?" appears twice in the transcript, both bubbles timestamped 00:17, each with its own copy button — it looks like the message was sent twice. But the session log contains exactly one real user message for that send, with the rest being automatically injected context (#10808). Count the data layer and the display layer separately and the mystery disappears.

DeepSeek Harness: Layer 1: the data layer really holds one

Only one event in the log has source.kind === "user"; the other same-role events are not yours.

  1. Open the session log session.v4.jsonl.zstd and locate the time of that send.
  2. You will see four user/message entries: the kind=user one is "Ready?".
  3. The other three are kind=memmy-memory, kind=runtime-context, and kind=time-context.
  4. The latter three also have role user, but they are not user input; cadence injects them automatically.
  5. So the data layer is clean: one input, no double billing, no duplicate answer.
text
00:17:41  user/message  kind=user             "Ready?"
00:17:41  user/message  kind=memmy-memory     "<memmy_l3_world_model ..."
00:17:41  user/message  kind=runtime-context  "Current runtime context ..."
00:17:41  user/message  kind=time-context     "Time sampled ..."

Four lines share one timestamp, but only the first is yours. That determines every later judgment: bubble count cannot be used to infer message count.

DSH plugin: Layer 2: why the display turns into two

The queued echo is hidden from the transcript but excluded from the deduplication set, so it renders as its own bubble.

  1. The frontend keeps a pending ledger, pendingSubmissions, recording the placement of each optimistically displayed message.
  2. The deduplication set localIds comes from pendingSubmissions.filter(s => s.placement !== "queued").map(s => s.requestId).
  3. Note that filter — queued is excluded from the set.
  4. On the other side, visibleSubmissions hides queued submissions from the transcript.
  5. But in the inboxSteering render logic, any source.kind === "user" with an rpcId looks itself up in localIds.
  6. Not found (because queued is not in the set) → this entry renders directly.
  7. After the message is persisted, the transcript renders it again → two bubbles.

DeepSeek Harness: Layer 3: why it only happens while queued

Sending while the agent is idle takes the next-turn path, where enqueue and dequeue happen almost simultaneously, so you see no duplicate.

  1. The event chain the reporter recorded: when sending during a run, the first agent/inbox/spliced targets next-step.
  2. A second splice follows with removedCount: 1.
  3. Only then does user/message kind=user appear.
  4. Another send while the agent was idle took next-turn, enqueue and dequeue happened together, and only one bubble appeared.
  5. Conclusion: the trigger is "the message enters the queued path", unrelated to plugins — the reporter ruled out third-party plugins one by one.

DSH Plugin: Layer 4: why the data layer is not a concern

It is only the display layer drawing one extra time; session content, model calls, and billing are unaffected.

  1. The model reads one user message.
  2. The copy button appears twice, but copies the same content.
  3. After a refresh or reopening the session, the bubble count should return to one.
  4. So it is an experience problem, not a data integrity problem.
  5. The report says so explicitly: "the data is fine, the frontend just rendered the same message twice".

DeepSeek Harness: Version status and fix

Two commits fixed this path, but both are in 0.2.2-alpha.2, not rc.4.

  1. The first, ae07093132d: keeps the transcript stable when a turn ends and a steering message lands.
  2. One of its descriptions reads "the queued echo waits for the Inbox projection rather than retiring on the persisted splice, so the queue dock does not blink for a frame".
  3. The second, a1659120a38: withdraws the echo when the queued echo's Inbox row is cancelled.
  4. Both commits changed session state files and their pending submission tests.
  5. Both are in f3803c96 (0.2.2-alpha.2), not in 504a01a9 (rc.4).
  6. The data layer needs no change, and neither does the log format.

DSH plugin: How to confirm this is the issue

All three signs together and you have it: character-identical content, identical timestamps, and exactly one kind=user in the log.

  1. Compare the two bubbles' text for exact equality, punctuation included.
  2. Compare timestamps down to the same minute.
  3. Count user/message entries with kind=user in the log.
  4. Recall the send timing: was the agent running a tool call at the time?
  5. Send another message while the agent is idle and see whether only one bubble appears.

Cautions

Count log events before assuming a duplicate send.

  1. Do not investigate the network as "duplicate sends". The log already proves there is one.
  2. Do not delete the session and start over. A refresh or reopening restores the single-bubble display.
  3. Do not mistake auto-injected events for user messages. Their role is user too.
  4. It still appears on rc.4. The fix is only on the alpha line.
  5. Attach timestamps and log counts when reporting. That is the fastest evidence separating a display issue from a real duplicate.

If your two bubbles differ slightly in content, they may be two real messages with completely different logic — check the log first.

Conversely, if the log really contains two kind=user entries, it really was sent twice, and you should investigate the input channel rather than rendering.See DeepSeek Harness blank sessions and missing auto titles for the related case.

FAQ

One message in DeepSeek Harness produces two identical user bubbles — was it sent twice?

No, it was not sent twice: the DeepSeek Harness session log for that send has exactly one event with source.kind === "user"; the rest are memory, runtime-context, and time-context events injected automatically by cadence. The two bubbles are a pure frontend display issue.

Why does it only happen in DeepSeek Harness when sending while the agent is running?

It only happens when sending while the agent is running because that send takes the queued path (placement === "queued") in DeepSeek Harness. The queued echo is hidden from the transcript yet also excluded from the deduplication set, so the queued entry renders as its own bubble, and the persisted message renders a second time.

Does it cause double billing or duplicate answers in DeepSeek Harness?

No, it does not cause double billing or duplicate answers: the DeepSeek Harness data layer holds one user message and the model processes it once. The issue affects display only, not session content or cost.

Which DeepSeek Harness version fixed it?

DeepSeek Harness fixed it in commits ae07093132d and a1659120a38 (both 10-27, after rc.4), and both are in 0.2.2-alpha.2 rather than rc.4. So the double bubble still appears on rc.4.

How do I quickly confirm this is the DeepSeek Harness issue?

To confirm the duplicate quickly in DeepSeek Harness, check whether the two bubbles have exactly the same timestamp and character-identical content, then count user/message events with kind=user in the session log; exactly one of each means a display-layer duplicate.

Related Terms

queued placement
Queued placement is the position marker used when a message is submitted while the agent is running. It puts the message into a queue first and merges it into the conversation when the current turn ends or the next step begins.— https://github.com/deepseek-ai/deepseek-harness/discussions/10808
pendingSubmissions
pendingSubmissions is the frontend ledger of pending messages, recording each optimistically displayed submission and its placement. Deduplication builds its set from the requestIds here.— https://github.com/deepseek-ai/deepseek-harness/discussions/10808
localIds
localIds is the deduplication set used during rendering, built from pending submission requestIds. The current implementation excludes queued submissions, so the queued entry is never deduplicated.— https://github.com/deepseek-ai/deepseek-harness/discussions/10808
agent/inbox/spliced
agent/inbox/spliced is the session event indicating an input was spliced into the current step or the next turn. It carries the target position and removal count, which reveals whether the message took the queue or the next-turn path.— https://github.com/deepseek-ai/deepseek-harness/discussions/10808

Sources