Skip to content

Web UI: session list empty on left panel when using web server mode #27837

Closed as not planned

Description

@RayDutchman

Description

When running opencode --web, the left panel session list is always empty in the web UI, even though /api/session returns sessions correctly.

Root Cause (Analysis)

The frontend loads sessions via SSE event-driven logic. When server.connected is received, the code iterates M.children (registered workspaces) to trigger session loading. However M.children is empty at the time the event arrives, so no sessions are ever loaded.

Related Bug

Sessions with time_archived stored as Unix millisecond integer cause /api/session to return 400 BadRequest for the entire list. The API schema expects DateTime.Utc. Workaround: set time_archived = NULL in SQLite DB.

Plugins

None

OpenCode version

v1.15.0

Steps to reproduce

  1. Start opencode in web server mode: opencode --web 0.0.0.0:4096
  2. Open browser, navigate to the web UI
  3. Left panel session list is empty
  4. /api/session API returns sessions correctly
  5. Search works and can find sessions
  6. Reproduced in incognito mode, different browsers, different devices

Screenshot and/or share link

Image

Operating System

Windows 11 running web server in WSL

Terminal

Web server mode (--web)

Activity

  1. github-actions commented on May 16, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues with a similar symptom (empty session list in Web UI). Please check:

    These issues share the same symptom (session list empty despite API returning data correctly) but may have different root causes. If your issue is specifically about the SSE server.connected event arriving before M.children is populated, it may be a distinct bug — please confirm whether the above issues describe the same behavior you're seeing.

  2. Aerytgophilis commented on May 28, 2026

    @Aerytgophilis

    Related reproduction from a WSL2 + Desktop GUI setup: #29766

    Same root cause (frontend timing: server.connected SSE fires before M.children is populated), but with additional evidence:

    • WSL server log shows zero session list requests from the GUI after handshake
    • curl and etch() from DevTools both return the correct session list
    • asar reverse-engineering confirms the loadSessions → M.children iteration path
    • A second compounding root cause: Windows paths are incorrectly resolved inside WSL (path.resolve() treats them as relative on Linux), causing project ID mismatches

    The dual-server architecture (vlocal sidecar + user-configured remote server) appears to exacerbate the timing issue, as the sidecar starts synchronously while remote server connections are asynchronous.

  3. orangepropeller commented on Jul 9, 2026

    @orangepropeller

    Same. The web UI session layout is currently broken.

  4. georgehaws commented on Jul 30, 2026

    @georgehaws

    +1

    Reproduced same issue from below:

    OpenCode 1.18.9
    Ubuntu 24.04 server
    Fedora + Brave client
    Access through Tailscale Serve HTTPS
    /session?directory=... returns all sessions correctly
    Root page says “Nothing here yet”
    New Session is inert
    Browser console remains blank
    Direct Base64 directory/session route works

  5. fyfirman commented on Aug 1, 2026

    @fyfirman

    Still reproduces on 1.18.10 and 1.18.11 (macOS arm64, opencode web, loopback). Adding a client-side mechanism that I think is distinct from the SSE race in the OP, since it discards sessions unconditionally rather than as a timing artifact.

    Symptom

    Home shows Nothing here yet / Create a session to get started while the backend is fully healthy:

    • GET /api/session?limit=5000&order=desc → 200, 8 sessions (7 root, none archived)
    • GET /project → 200, 3 projects
    • No console errors, no failed requests

    So the data reaches the client and is then dropped during render.

    Mechanism

    The home session list joins every session to a project and drops it when no project matches. From the production bundle (assets/index-Ctki20Mg.js, 1.18.11), the list builder:

    [...new Map(n.map(r => [r.id, r])).values()]
      .sort(/* by time.updated */)
      .flatMap(r => {
        const i = rt(r.directory)
        const s = e.projects().find(o => rt(o.worktree) === i || o.sandboxes?.some(a => rt(a) === i))
          ?? QE(r, e.projects(), e.projectByID())
        return s ? { session: r, project: s, projectName: Dl(s) } : []   // <-- dropped here
      })

    and the fallback resolver:

    function QE(e, t, n = new Map(t.flatMap(r => r.id ? [[r.id, r]] : []))) {
      const r = n.get(e.projectID)
      if (r) return r
      const i = rt(e.directory)
      return t.find(s => rt(s.worktree) === i || s.sandboxes?.some(o => rt(o) === i))
    }

    The important detail is that e.projects() is the client-side opened-projects list, not the /project response. It is populated only by projects.open():

    open(s) {
      const o = e.scope(), a = rt(s), l = r()
      l.some(c => rt(c) === a) && t("recentlyClosed", o, l.filter(c => rt(c) !== a))
      !n().some(c => c.worktree === s) && t("projects", o, [{ worktree: s, expanded: true }, ...n()])
    }

    On a profile where nothing has been opened, e.projects() is [], so both the direct match and QE return undefined and every session hits return []. The server's project list never feeds this path — I confirmed /project is fetched but only consulted for matching, and /api/project + /api/project/current are declared in the SDK yet return the SPA HTML fallback with 200 rather than JSON.

    Why this is hard to escape

    Both recovery paths out of the empty state are also broken, so the UI is a dead end on a fresh profile:

    Calling /api/fs/list directly works and returns 125 entries for the same directory, so the server side is fine.

    Not environment-specific

    Ruled out on my side:

    • Same result on 1.18.10 and 1.18.11 (different bundle hashes, identical behaviour)
    • Same result launching from a real git worktree as from $HOME
    • Same result on a fresh browser profile with empty localStorage
    • Sessions verified as root and unarchived (parentID: null, time.archived: null), so the archived-timestamp issue noted in the OP is not in play here

    Workaround

    Downgrading to 1.17.20 — the last release before the v2 layout landed in 1.18.0 — restores a working UI: projects list, session composer, and all existing sessions reachable via search. Related: #37012.

  6. YouFoundJK commented on Sep 8, 2026

    @YouFoundJK

    Same for me as well. I have a session literally running in the tab as seen in the below screenshot, Despite that, the home never gets populated even after refreshing.

    Image
  7. vector0902 commented on Sep 25, 2026

    @vector0902

    FYI — I hit this too (opencode --port / web server mode, Home shows "Nothing here yet"
    while /api/session + /project return full data; matches the "client-side opened-projects
    join drops every session" analysis above, verified in current dev source).

    I implemented a small workaround at the TUI level, that sidesteps the empty Home list
    entirely: a --open flag , which makes opencode --port X --open ,
    which auto-opens the exact session
    deep link (/server/<base64url(serverUrl)>/session/<id>) whenever a session starts/
    resumes/switches in the TUI,

    (dedup: same session opens once). Since the deep link route
    works (confirmed in this thread), this gives a reliable path to the current session without
    depending on the Home list.

    Commit (on a dev-synced fork, 6 files, 9 unit tests):
    vector090-org1@fb726e6

    Happy to open a PR against dev if it looks useful.

  8. thdxr commented on Oct 11, 2026

    @thdxr
    Member

    Thanks for the report! OpenCode 2.0 is now out and development is focused on V2, so we're closing issues filed against OpenCode 1. Please upgrade (opencode upgrade --major, details: https://anoma.ly/notes/opencode-2-0), and if this is still relevant on 2.0, reopen this issue or open a new one with your 2.0 version.

    — from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊

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

Metadata

Metadata

Assignees

No one assigned

    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