Skip to content

Session.list() includes archived sessions in LIMIT window, causing unarchived sessions to disappear from sidebar #24850

Closed as not planned
shoootyou/opencode
#18

Description

@simianhacker

Summary

Sessions disappear from the Web UI sidebar after archiving other sessions, because the server-side Session.list() query includes archived sessions in its LIMIT window, which are then stripped client-side by trimSessions.

Steps to Reproduce

  1. Accumulate many sessions in a project (e.g., 100+ root sessions)
  2. Archive a batch of old sessions
  3. Observe that archiving bumps time_updated on each archived session
  4. The sidebar now shows fewer sessions than expected — some previously visible unarchived sessions have disappeared

Root Cause

The instance-scoped Session.list() function (packages/opencode/src/session/session.ts) does not filter out archived sessions:

export function* list(input?) {
  const conditions = [eq(SessionTable.project_id, project.id)]
  // ... directory, roots, start, search filters
  // NOTE: no isNull(SessionTable.time_archived) condition
  const rows = Database.use((db) =>
    db.select().from(SessionTable)
      .where(and(...conditions))
      .orderBy(desc(SessionTable.time_updated))
      .limit(limit)
      .all()
  )
}

In contrast, listGlobal() does have this filter:

if (!input?.archived) {
  conditions.push(isNull(SessionTable.time_archived))
}

The client-side trimSessions() strips archived sessions after the fact:

const all = input
  .filter((s) => !!s?.id)
  .filter((s) => !s.time?.archived)  // <-- client-side filtering

So the flow is:

  1. Server fetches top N sessions by time_updated DESC — including archived ones
  2. Recently archived sessions have bumped time_updated, so they fill the top of the result set
  3. Client strips archived sessions, leaving fewer than limit unarchived sessions
  4. Older unarchived sessions that were pushed past the server-side limit are silently lost

Expected Behavior

The instance-scoped list() should exclude archived sessions server-side (matching listGlobal's behavior), so the full limit is used for unarchived sessions.

Suggested Fix

Add isNull(SessionTable.time_archived) to the conditions in Session.list():

export function* list(input?) {
  const conditions = [eq(SessionTable.project_id, project.id)]
  conditions.push(isNull(SessionTable.time_archived))  // <-- add this
  // ...
}

Or, if there's a use case for listing archived sessions via this route, gate it the same way listGlobal does:

if (!input?.archived) {
  conditions.push(isNull(SessionTable.time_archived))
}

Environment

  • OpenCode v1.4.10 (Homebrew)
  • macOS (darwin-arm64)
  • ~100 root sessions in a single project

Activity

  1. added
    coreAnything pertaining to core functionality of the application (opencode server stuff)
    on Apr 28, 2026
  2. simianhacker commented on Apr 28, 2026

    @simianhacker
    Author

    Possibly related:

    This issue identifies a specific server-side root cause: Session.list() doesn't exclude archived sessions from the query, so archived sessions consume LIMIT slots that get discarded client-side by trimSessions. This is especially visible after bulk-archiving sessions, since archiving bumps time_updated and pushes the archived sessions to the top of the result set.

  3. simianhacker commented on Apr 28, 2026

    @simianhacker
    Author

    Workaround

    Until this is fixed, if an active session disappears from the sidebar after archiving, you can bump it back into the fetch window by touching its time_updated via the API:

    curl -X PATCH "http://<host>:<port>/session/<session-id>?directory=<project-directory>" \
      -H "Content-Type: application/json" \
      -d '{"title": "<current title>"}'

    This sets time_updated to now, pushing the session to the top of the list.

    Visiting the session directly in the Web UI also bumps it, but navigating away and back may cause it to disappear again if it falls below the fetch limit.

  4. removed
    coreAnything pertaining to core functionality of the application (opencode server stuff)
    on May 3, 2026
  5. github-actions commented on Jul 3, 2026

    @github-actions
    Contributor

    To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.

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