You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Clearing time.archived silently fails, so archived sessions cannot be restored #47849
Clearing time.archived on a session returns HTTP 200 and does nothing, so a session can be archived but never restored. Two independent defects sit on that path, and either one alone is enough to make it unreachable — which is why adding an "Unarchive" button doesn't fix it.
1. packages/core/src/session/projector.ts
time_archived: info.time.archived,
This passes undefined when the timestamp is being cleared. Drizzle omits undefined keys from .set(), so that means "leave this column alone", not "set NULL". The row keeps its previous value.
2. The session update handler (server/routes/instance/httpapi/handlers/session.ts)
A client clearing the field sends {"time":{}}, because JSON.stringify drops undefined-valued properties. So the guard short-circuits and setArchived is never called.
Note ArchivedTimestamp is Schema.Finite and deliberately accepts 0 and negative values for legacy compatibility, so a truthiness check on archived is also incorrect — a session stored with 0 reads as active.
OpenCode version
dev @ 1b937c8 (also present in every version with the current projector)
@nexxeln this fixes #47849, which is assigned to you. I reduced it to four backend/test files; the TUI and web changes are separate. The regression test archives, clears, and re-reads the session to check persistence. Could you take a look and approve the gated workflows, or point me to the right maintainer? Thanks!
The session reappeared in GET /session and in the web UI sidebar after a reload.
That is consistent with the projector.ts diagnosis in the report rather than against it. 0 is a defined value, so Drizzle keeps the key in .set() and the column is written; undefined gets dropped and the row keeps its previous timestamp. So the bug is specifically that the cleared state is represented by a value Drizzle elides — not that the column is unwritable.
If the fix lands as "write null", it is worth confirming readers treat 0 and null identically, since 0 rows now exist in the wild from anyone who used this workaround. In my case GET /session returned archived: 0 and both the list endpoint and the sidebar treated it as not archived, so the read path already appears falsy-based rather than null-based.
Context on how the session got archived, which is why restore matters: session.archive is bound to mod+shift+backspace. Ctrl+Backspace is delete-previous-word, so holding Shift from a text selection archives the current session instead — silently, with no confirmation and no toast. Easy to trigger by accident, and at that point the session looks deleted.
Thanks for the detailed report! In 2.1.0, sessions can be restored by updating them with archived: false; restoring now clears the saved archive timestamp rather than silently leaving it unchanged.
Update with opencode upgrade or npm i -g @opencode/cli@latest (desktop: update the app). Please reopen or comment if restoration still fails on that version or newer.
Activity
alohaninja commentedon Sep 17, 2026
@nexxeln this fixes #47849, which is assigned to you. I reduced it to four backend/test files; the TUI and web changes are separate. The regression test archives, clears, and re-reads the session to check persistence. Could you take a look and approve the gated workflows, or point me to the right maintainer? Thanks!
PaoloC68 commentedon Sep 28, 2026
Data point that narrows this down: clearing is not universally broken — the failure depends on which falsy value is sent.
On v1.18.31 I recovered an accidentally archived session by sending
0rather than null/undefined:Before:
time_archived = 1790608774698After:
time_archived = 0The session reappeared in
GET /sessionand in the web UI sidebar after a reload.That is consistent with the
projector.tsdiagnosis in the report rather than against it.0is a defined value, so Drizzle keeps the key in.set()and the column is written;undefinedgets dropped and the row keeps its previous timestamp. So the bug is specifically that the cleared state is represented by a value Drizzle elides — not that the column is unwritable.Two practical consequences:
PATCHwitharchived: 0. That matters because with no unarchive UI ([FEATURE]: Add unarchive/restore for archived sessions #24153, [FEATURE]:unarchive sessions #41403, feat(app): view archived sessions & unarchive #15250, [FEATURE]: view archived sessions on desktop #6680), this is the only way back and it is worth having findable while fix(session): clear time.archived so archived sessions can be restored #47848 is unmerged.null", it is worth confirming readers treat0andnullidentically, since0rows now exist in the wild from anyone who used this workaround. In my caseGET /sessionreturnedarchived: 0and both the list endpoint and the sidebar treated it as not archived, so the read path already appears falsy-based rather than null-based.Context on how the session got archived, which is why restore matters:
session.archiveis bound tomod+shift+backspace.Ctrl+Backspaceis delete-previous-word, so holding Shift from a text selection archives the current session instead — silently, with no confirmation and no toast. Easy to trigger by accident, and at that point the session looks deleted.neriousy commentedon Oct 20, 2026
Thanks for the detailed report! In 2.1.0, sessions can be restored by updating them with
archived: false; restoring now clears the saved archive timestamp rather than silently leaving it unchanged.Update with
opencode upgradeornpm i -g @opencode/cli@latest(desktop: update the app). Please reopen or comment if restoration still fails on that version or newer.