Skip to content

bug(runtime-host): a queue drained while no root Turn is live is never projected — Desktop keeps a phantom queued card and retract fails with not_found #5520

Description

@MoonOld

What happened

The composer keeps rendering a phantom queued-message card after the Runtime Host queue no longer holds that entry. Every attempt to delete it fails with not_found and a generic 操作失败 / 任务操作失败,请稍后重试。 toast, and the card never goes away.

Observed while sending the next message in a session that had a follow-up entry queued ("下一轮 · 每轮一条"):

ERROR Error occurred in handler for 'sessions:retractQueueEntry': RuntimeHostOperationError: Message queue entry does not exist
    at #acceptResponse (@maka/runtime-host/dist/client/connection.js:414:24)
  operation: 'queue.entry.retract',
  code: 'not_found'

14 identical failures in ~4.3s (2026-09-20T04:03:14.700Z → 04:03:18.297Z, ~170ms apart), i.e. one renderer IPC call per click, with no main-process retry involved.

Expected

Either the card disappears as soon as the Host queue no longer holds the entry, or a retract of an entry the Host no longer has converges the local projection (already-settled / idempotent) instead of surfacing a generic failure.

How to reproduce

  1. In a session with a running Turn, submit a follow-up message (Enter = next turn). The composer's queue strip shows the card with 编辑 / 调整方向 / 删除.
  2. Leave that session (switch to another one, or let it sit) so the queued entry leaves the Host queue while no root Turn is live in the snapshot this renderer last observed — e.g. the follow-up is consumed and the Session goes idle, or a drain happens off-subscription.
  3. Come back to the session. The card is still rendered as queued, with 删除 enabled.
  4. Click 删除. Nothing is deleted: the toast 操作失败 / 任务操作失败,请稍后重试。 appears and the card stays. Clicking again repeats it indefinitely.

Intermittent by nature (it needs a queue change to land while the client is not observing a live Turn), but once the projection is stale it is stuck — reloading the renderer (Cmd+R) or restarting the app clears it, switching sessions back and forth does not.

Environment

  • Maka: 0.2.0-dev.38.20260916 — packaged, nightly channel
  • Surface: Desktop (macOS, arm64)
  • Electron 43.4.1 · Chrome 150.0.7871.224 · Node 24.18.1 · darwin 25.4.0
  • Locale: zh-CN
  • Runtime Host: protocol v0, compatibility 157, epoch b3572bc0-cf03-44fa-ab94-fde952e24a6f, healthy ("ready", 1 connection)
  • Long-lived process: main-process and Runtime Host uptime ~161,200s (~45h) at capture time

Logs, screenshots, or additional context

Analysis (line references from eb23ac92)

The failing operation is the renderer asking the Host to delete a queue entry the Host no longer has — packages/runtime-host/src/server/message-coordinator.ts:1766 (#retractQueuedEntryAdmitted): a missing entryId returns exactly this not_found; an in-flight entry would return operation_conflict, an archived Session session_archived, neither of which appears here.

The card is stale local state, not Host state:

  • The Desktop queue projection is driven only by queue_update events — apps/desktop/src/renderer/app-shell-session-events.ts:306 (messageQueueBySession); there is no snapshot fallback.
  • The Host only pushes queue_update when the queue actually changed and a root Turn exists: packages/runtime-host/src/adapter/session-projector.ts:437 (if (root && queueChanged(previousSnapshot.queue, next.queue))), and the reconnect seed bails out on no Turn: same file :165 (seedActive: const root = this.#snapshot.rootTurn; if (!root) return [];).

So a queue that drains while no root Turn is live is never projected, and the renderer's non-empty messageQueueBySession entry survives indefinitely — the composer keeps it renderable with entry.state === 'queued', which is what keeps 删除 enabled (packages/ui/src/composer-message-queue.tsx:286).

The failure path also deliberately leaves the projection untouched ("the projection is unchanged on failure, so there is nothing to settle here"), and the toast is the generic queue-action surface — apps/desktop/src/renderer/app-shell.tsx:1793 deleteQueuedEntryrunQueueEntryActionshowSessionError(operationFailedTitle, localizedShellErrorMessage(...)) at :1816. not_found is not a class classifyGeneralizedError recognizes (packages/core/src/redaction.ts:235 covers timeout / rate_limited / auth_failed / provider_error / network_error only), so it renders the fallback line and is reported as an unexpected-operation diagnostic.

No main-process retry is involved: the sessions:retractQueueEntry handler is a single direct call (apps/desktop/src/main/runtime-host-session-execution-ipc-main.ts:650); retryDispatchedCommand only covers one reconnect retry and only on the stop path.

Likely fix directions

  1. Runtime Host: drop the root gate on queue_update (emit on queue change even with no live root Turn), and let seedActive seed the queue (even empty) when there is no root Turn, so clients can converge on reconnect.
  2. Desktop: treat not_found (and session_archived) on queue.entry.retract as already-settled — remove the entry from the local projection instead of showing 操作失败, since the user's intent is already satisfied. Same for promote / update / reorder.
  3. Copy: route these stable codes through an explicit message instead of the generic fallback + unexpected-operation diagnostic.

Additional context

Two other error families in the same diagnostic report look like corroborating (not causal) evidence that this long-lived session had dropped events:

[2026-09-20T03:21:02Z] ERROR handler 'sessions:listActiveInteractions': Error: Runtime Host Session observer closed while opening
[2026-09-20T03:32:43Z] ERROR handler 'skills:listInvocable': RuntimeHostOperationError: Session is archived (session_archived, skill.catalog.invocable.query)

Card as rendered (screenshot, zh-CN): header 下一轮 每轮一条, body babeside的 amazon也不需要同步了, actions 编辑 / 调整方向 / 删除.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions