Skip to content

Stale "busy" in session_status never clears - session shows "working" forever (bootstrap uses bare setStore, not reconcile) #32127

Closed as not planned

Description

@zoulukuang

Summary

A session can show the "working" indicator forever. session_working(id) is derived purely from session_status (in child-store.ts: (session_status[id]?.type ?? "idle") !== "idle"), but the frontend's session_status is reconciled from session.status() using a bare setStore instead of reconcile — so an entry the backend no longer reports as busy is never removed from the store.

Root cause

In packages/app/src/context/global-sync/bootstrap.ts, two adjacent lines handle full-snapshot data differently:

// config — reconcile, correctly drops removed keys
retry(() => input.sdk.config.get().then((x) => input.setStore("config", reconcile(x.data!, { merge: false }))))

// session_status — bare setStore, cannot drop removed keys
retry(() => input.sdk.session.status().then((x) => input.setStore("session_status", x.data!)))

session.status() returns only non-idle sessions — idle ones are deleted from the in-memory map in packages/opencode/src/session/status.ts:

if (status.type === "idle") {
  yield* events.publish(Event.Idle, { sessionID })
  data.delete(sessionID)
  return
}

SolidJS merges object keys on setStore — it does not remove keys absent from the new value. So a stale { ses_x: "busy" } in the store survives when session.status() no longer includes ses_x, and session_working(ses_x) stays true permanently.

When it happens

Whenever the store holds a busy/retry entry that the backend has since cleared but the corresponding session.idle event didn't reach the store — e.g. it was dropped during a brief disconnect, or the server restarted and lost its in-memory status map. On the next bootstrap / reconnect, session.status() comes back without that session, but the bare merge keeps it busy, so the session is stuck "working" with no way to clear it short of a full client restart.

Fix

Reconcile session_status the same way the adjacent config line already does:

input.setStore("session_status", reconcile(x.data ?? {}, { merge: false }))

PR incoming.

Activity

  1. github-actions commented on Jun 13, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of an existing issue. Please check:

  2. zoulukuang commented on Jun 13, 2026

    @zoulukuang
    Author

    Duplicate of #17657 (same root cause and fix). Closing in favor of it. The fix is up at #32128.

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