zai-org / zai-org/feedback

[Bug] Queued user inputs are silently discarded with `status_reason: session_resumed` when a session resumes

Open
#379 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

priority: P2
Dominant language
No language data
Stars
22
Forks
1
PR merge metrics
No merged PRs in 30d

Description

Pre-submission checklist
  • I searched existing Issues and Discussions; no report covers queued inputs being persisted as discarded/session_resumed.
  • I read CONTRIBUTING.md.
  • User message bodies, local username, workspace path, trace IDs, and request IDs are omitted or sanitized.
Category

Agent chat / queue persistence / session recovery

Agent framework

ZCode Agent (first-party)

Severity

Blocking. Inputs shown as queued in the UI disappear without being sent or restored. Their text is recoverable only by querying the local SQLite database directly.

Reproducibility

One fully captured incident. All seven queued inputs in the affected session were discarded in the same resume operation.

Description

With interaction behavior set to queue, follow-up sendText inputs can remain queued while a background turn is running or retrying. When the client later resumes that session, every queued-but-unpromoted input is silently changed to:

delivery = queue
status = discarded
status_reason = session_resumed

The queued chips disappear from the UI. The inputs are not promoted into a later turn and are not restored to the composer. Their payloads remain in SQLite, but the product provides no visible recovery path.

Environment
  • ZCode Desktop: 3.9.2.6069
  • Session/runtime schema version: 0.16.5
  • OS: Fedora Linux 44, x86_64
  • Desktop: GNOME / Wayland
  • Model: GLM-5.3-Flash through the built-in Z.ai provider
  • Transport: Anthropic-compatible endpoint over SSE
  • Interaction behavior: queue
Verified persistence evidence

Source: ~/.zcode/cli/db/db.sqlite, table session_input.

For one session (identifier shortened to sess_abce396c…):

  • 7 rows had kind = sendText and delivery = queue.
  • They were created from 2026-08-27 09:55:34.835 through 10:44:34.973 local time (UTC+8).
  • Their admitted_sequence values were 7, 8, 10, 13, 14, 15, 16.
  • Every row had promoted_sequence = NULL and promoted_message_id = NULL.
  • All 7 were changed to status = discarded, status_reason = session_resumed during one 11 ms burst at 10:58:33.071–10:58:33.082.
  • The CLI log then recorded event = session.resumed for the same session at 10:58:33.350, with appliedMessageCount = 267 and interruptedToolCount = 1.
  • The seven payload bodies still exist in the database and were successfully recovered manually. They are intentionally omitted here because they contain unrelated project instructions.

Sanitized row shape:

kind      delivery  status     status_reason    promoted_sequence  promoted_message_id
sendText  queue     discarded  session_resumed  NULL               NULL
Related runtime behavior observed before the resume

The same session had repeated 60-second SSE idle timeouts and retries:

event = model.stream.stalled
statusMessage = "Model stream stalled: no event received for 60000ms."
maxAttempts = 11
maxRetries = 10

It also logged two active-turn cancellations whose cause was:

"v4 sendQueuedNow preempts active turn"

This may explain how a long-lived queue accumulated, but the primary defect in this report is independent: a resume operation must not silently discard persisted, unpromoted user inputs.

Steps to reproduce
  1. Set ZCode interaction behavior to queue.
  2. Start a turn that remains active for long enough to queue follow-up messages. A throttled connection that triggers the 60-second stream idle timeout makes this easier to reproduce.
  3. Send several follow-up messages while the turn is active and confirm that queued chips are visible.
  4. Trigger the client/runtime path that resumes the session (for example, allow the task/runtime to end and then reopen or resume the session).
  5. Observe that the queued chips disappear and no corresponding user messages are sent or restored.
  6. Inspect session_input: affected rows are discarded with status_reason = session_resumed, while both promotion fields are NULL.
Expected behavior
  • Session resume must preserve queued-but-unpromoted inputs.
  • After recovery, inputs should either remain queued, be promoted in original order, or be restored to the composer for user confirmation.
  • If an input cannot be recovered automatically, the UI should expose it and explain the failure; it must not disappear silently.
  • Queue state transitions should be crash-safe/transactional so a resume cannot destroy the only user-visible copy.
Actual behavior

All seven queued inputs disappeared from the UI during resume and were permanently marked discarded. None was promoted. Manual SQLite inspection was required to recover their text.

Related issues
  • #3 concerns queued-message controls in the UI; it does not cover loss during resume.
  • #174 covered session switching cancelling an in-flight turn and was closed as fixed in v3.5.2. The same sendQueuedNow preempts active turn cause is still present here in v3.9.2, but only as preceding context.
  • #276 concerns completed messages that are persisted but temporarily not rendered; in this report the inputs are explicitly marked discarded and never delivered.

Sanitized database rows and log excerpts can be supplied if maintainers need more detail.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the client/runtime path that emits event = session.resumed and updates rows in the session_input table, especially the sendQueuedNow preempts active turn path. Reproduce with queued inputs, then verify that unpromoted rows remain queued, are promoted in order, or are visibly restored rather than marked discarded/session_resumed.

Written by the indexing model from the issue text.

Assessment

Tech stack
sqlite
Domain
database, desktop
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.