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
When connecting the Windows Desktop GUI (Electron) to an opencode serve instance running inside WSL2, the session sidebar remains completely empty even after:
The connection handshake succeeds (green indicator)
The server API returns sessions correctly via direct curl / fetch()
Sessions exist in the server SQLite database
Two root causes were identified:
Frontend timing issue -- session loading is triggered by SSE events that fire before the workspace/project list is populated
Path concatenation in WSL -- Windows paths sent by the GUI are incorrectly resolved inside WSL, causing project ID mismatches
Inside WSL filesystem (~/opencode_workspace, a git repo)
Note: The same WSL2 + Desktop GUI setup was tested on a different Windows 11 machine (office PC) and the sidebar displayed sessions correctly. This suggests the bug may be environment/state-specific rather than universally reproducible.
Architecture (Dual-Server)
The Desktop GUI has a dual-server architecture that is central to this bug:
Even when defaultServerUrl is set to the WSL server (http://127.0.0.1:8193), the vlocal sidecar is still spawned automatically on startup. The GUI initial session loading appears to depend on SSE events that fire before the workspace/project list is fully populated.
Steps to Reproduce
In WSL2, start opencode serve from a git repo directory:
Running the same query from the GUI DevTools Console also returns all sessions:
fetch("http://127.0.0.1:8193/session?roots=true&limit=55").then(r=>r.json()).then(data=>console.log("Sessions:",data.length,data.map(s=>s.title)))// -> Sessions: 14 ["Session Title 1", "Session Title 2", ...]
2. No session list request observed in WSL server log
After the GUI connects, no session list API call was observed in the WSL server log (at INFO level):
INFO ... service=server global event connected
No GET /session request was logged at any point after the GUI handshake. The server.connected SSE event fires, but the session loading logic does not appear to be triggered. Note: session list requests may not be logged at INFO level, so this observation is based on the available log output.
3. GUI is connected to both servers simultaneously
The loadSessions call is triggered by the server.connected SSE event handler, but at that point M.children (the registered workspace/project list) is still empty, causing the iteration to produce no session-loading actions.
Root Cause 1: Frontend Timing (SSE vs. Project Hydration Race)
The session sidebar loading is driven by SSE event handlers in the renderer process. When server.connected fires:
The handler iterates over M.children (registered workspaces/projects)
For each workspace, it calls loadSessions(worktree)
But when this event fires, M.children is empty
No sessions are ever loaded
This is a race condition between SSE connection establishment and project/workspace state hydration. The server.connected event arrives before the project restore logic has finished populating the workspace list.
The vlocal sidecar works around this because it starts first (synchronously with the app) and its project list is loaded from local state before any remote connections are attempted.
Root Cause 2: Path Concatenation in WSL
Even if the timing issue were resolved, a second bug prevents session matching.
The chain:
Step 1: GUI reads worktree from global.dat
-> "C:/Users/{user}/opencode_workspace"
Step 2: GUI sends this as the directory parameter
-> GET /session?directory=C:/Users/{user}/opencode_workspace&roots=true
Step 3: WSL server receives the path and calls AppFileSystem.resolve()
-> path.resolve("C:/Users/{user}/opencode_workspace")
Step 4: On Linux, path.resolve() treats this as a relative path
-> CWD is prepended: "/home/{wsl-user}/C:/Users/{user}/opencode_workspace"
Step 5: This path does not exist on the WSL filesystem
-> projectV2.resolve() cannot find .git
-> Falls back to projectID = "global"
Step 6: Sessions in DB were created from the actual git repo
-> project_id = "{git_worktree_hash}" != "global"
-> listByProject() WHERE clause: eq(project_id, "global") matches nothing
-> Returns 0 sessions
On Linux (WSL), windowsPath2() is a no-op. path.resolve("C:/Users/...") treats the Windows path as relative, prepending the server CWD. The resulting path never matches the actual git repository location.
This is a variant of the path separator issue documented in #21340, but specific to the WSL cross-filesystem scenario.
Related Issues / PRs
#17451 -- Sessions keyed only by directory, no server identity component (architectural root cause of dual-server state collision)
#18302 -- Multi-server layout state not namespaced per server (OPEN, proposes Option B: namespace by origin())
#27837 -- Web server mode sidebar empty (frontend timing bug, same Root Cause 1)
#19348 -- Sessions not shown in sidebar when connected to non-localhost server (same symptom, DB normalization only partially effective)
#17765 -- Windows Desktop loses session history after restart (project/worktree mapping mismatch)
Workaround
Use opencode CLI (TUI) inside WSL2 directly. The TUI runs entirely within the WSL environment so there is no path mismatch or dual-server timing issue.
Alternatively, work only through the vlocal sidecar (the built-in connection), accepting that historical sessions from the WSL database will not be visible in the sidebar.
Expected Behavior
When the Desktop GUI successfully connects to a remote opencode serve instance (including WSL2), the session sidebar should display all sessions from that server database.
Actual Behavior
The sidebar is empty. The vlocal sidecar empty database is used for session display, while the WSL server sessions are never loaded despite a successful connection.
Summary
When connecting the Windows Desktop GUI (Electron) to an
opencode serveinstance running inside WSL2, the session sidebar remains completely empty even after:curl/fetch()Two root causes were identified:
Environment
--hostname 0.0.0.0 --port 8193http://127.0.0.1:8193(WSL port-forwarded)~/opencode_workspace, a git repo)Note: The same WSL2 + Desktop GUI setup was tested on a different Windows 11 machine (office PC) and the sidebar displayed sessions correctly. This suggests the bug may be environment/state-specific rather than universally reproducible.
Architecture (Dual-Server)
The Desktop GUI has a dual-server architecture that is central to this bug:
Even when
defaultServerUrlis set to the WSL server (http://127.0.0.1:8193), the vlocal sidecar is still spawned automatically on startup. The GUI initial session loading appears to depend on SSE events that fire before the workspace/project list is fully populated.Steps to Reproduce
In WSL2, start opencode serve from a git repo directory:
Open the Windows Desktop GUI (v1.15.11).
Add a server connection to
http://127.0.0.1:8193.Set it as default:
Observe: The connection indicator shows green ("connected"), but the session sidebar is empty.
Evidence
1. Server API works correctly (curl / fetch)
Running the same query from the GUI DevTools Console also returns all sessions:
2. No session list request observed in WSL server log
After the GUI connects, no session list API call was observed in the WSL server log (at INFO level):
No
GET /sessionrequest was logged at any point after the GUI handshake. Theserver.connectedSSE event fires, but the session loading logic does not appear to be triggered. Note: session list requests may not be logged at INFO level, so this observation is based on the available log output.3. GUI is connected to both servers simultaneously
The GUI maintains active TCP connections to both the vlocal sidecar and the WSL server, but only loads sessions from vlocal.
4. global.dat confirms the WSL server is the default
{ "server": { "list": [{"type": "http", "http": {"url": "http://127.0.0.1:8193"}}], "projects": {"local": [{"worktree": "C:/Users/{user}/opencode_workspace", "expanded": true}]}, "lastProject": {"local": "C:/Users/{user}/opencode_workspace"} } }Despite the correct server and project configuration, sessions are not loaded.
5. Confirmed by asar reverse-engineering
Decompiling
app.asarreveals the session loading flow:The
loadSessionscall is triggered by theserver.connectedSSE event handler, but at that pointM.children(the registered workspace/project list) is still empty, causing the iteration to produce no session-loading actions.Root Cause 1: Frontend Timing (SSE vs. Project Hydration Race)
The session sidebar loading is driven by SSE event handlers in the renderer process. When
server.connectedfires:M.children(registered workspaces/projects)loadSessions(worktree)M.childrenis emptyThis is a race condition between SSE connection establishment and project/workspace state hydration. The
server.connectedevent arrives before the project restore logic has finished populating the workspace list.The vlocal sidecar works around this because it starts first (synchronously with the app) and its project list is loaded from local state before any remote connections are attempted.
Root Cause 2: Path Concatenation in WSL
Even if the timing issue were resolved, a second bug prevents session matching.
The chain:
Key code (
AppFileSystem.resolve()):On Linux (WSL),
windowsPath2()is a no-op.path.resolve("C:/Users/...")treats the Windows path as relative, prepending the server CWD. The resulting path never matches the actual git repository location.This is a variant of the path separator issue documented in #21340, but specific to the WSL cross-filesystem scenario.
Related Issues / PRs
origin())Workaround
Use
opencodeCLI (TUI) inside WSL2 directly. The TUI runs entirely within the WSL environment so there is no path mismatch or dual-server timing issue.Alternatively, work only through the vlocal sidecar (the built-in connection), accepting that historical sessions from the WSL database will not be visible in the sidebar.
Expected Behavior
When the Desktop GUI successfully connects to a remote
opencode serveinstance (including WSL2), the session sidebar should display all sessions from that server database.Actual Behavior
The sidebar is empty. The vlocal sidecar empty database is used for session display, while the WSL server sessions are never loaded despite a successful connection.