[Bug] Queued user inputs are silently discarded with `status_reason: session_resumed` when a session resumes
Nobody has claimed this yet.
- 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-Flashthrough 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 = sendTextanddelivery = queue. - They were created from
2026-08-27 09:55:34.835through10:44:34.973local time (UTC+8). - Their
admitted_sequencevalues were7, 8, 10, 13, 14, 15, 16. - Every row had
promoted_sequence = NULLandpromoted_message_id = NULL. - All 7 were changed to
status = discarded,status_reason = session_resumedduring one 11 ms burst at10:58:33.071–10:58:33.082. - The CLI log then recorded
event = session.resumedfor the same session at10:58:33.350, withappliedMessageCount = 267andinterruptedToolCount = 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
- Set ZCode interaction behavior to
queue. - 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.
- Send several follow-up messages while the turn is active and confirm that queued chips are visible.
- Trigger the client/runtime path that resumes the session (for example, allow the task/runtime to end and then reopen or resume the session).
- Observe that the queued chips disappear and no corresponding user messages are sent or restored.
- Inspect
session_input: affected rows arediscardedwithstatus_reason = session_resumed, while both promotion fields areNULL.
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 turncause 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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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