Skip to content

Desktop: white screens & send failures from corrupted global state JSON, stale session.path, dangling server refs (1.18.3, Windows + WSL) #37353

Closed as not planned

Description

Description

Environment: Desktop 1.18.3 (Electron, ai.opencode.desktop) on Windows 11, server running as WSL sidecar (Ubuntu-24.04, opencode server 1.18.1, WSL2 mirrored networking). CLI 1.17.18 also installed. Two separate databases exist: Windows (%USERPROFILE%.local\share\opencode\opencode.db) and WSL (~/.local/share/opencode/opencode.db).

Over ~9 days the desktop app degraded through: white screen at launch (Session not found, 404) → sessions browsable but sending fails ("cannot get session") → white screen on server switch (Session not found, different id) → white screen after deleting a custom server (Notification server not found: http://localhost:4097).

Root causes identified (evidence in the attached full report + debug log bundle):

  1. Global state file corrupted by an unescaped newline (most severe). opencode.global.dat had an error message (stack trace containing raw \n) written unescaped into a JSON string. The whole file then failed to parse ("Bad control character in string literal"), every store-get/store-set threw, and all stateful UI operations — including sending messages — broke. The file mtime froze on the day of corruption: UI state silently failed to persist for 9 days. Suggest validating/escaping on serialize, and on parse/write failure backing up + resetting the file instead of failing forever.

  2. Event-sourced projection rows deleted without events. 18 sessions had intact event logs (up to 46k events) but missing session/message/part projection rows; no session.deleted event exists anywhere in the DB. Restoring "last session" then 404s and white-screens. Suggest a db repair/rebuild-projections command and writing tombstone events on delete.

  3. Stale absolute paths in session.path. Sessions moved between directories keep absolute paths (legacy convention; current is '' for project-root sessions). The server joins worktree+path → realPath NotFound → "cannot get session" on send. Present in both DBs. Suggest normalizing on write plus a cleanup migration.

  4. No fallback for dangling references. "Last session" / home.selection / tabs pointers are stored per server and trusted blindly; when the pointed session or server is gone (the two DBs' session sets had diverged), the renderer throws Session not found / Notification server not found and white-screens instead of ignoring the stale pointer and falling back to a default view.

  5. WSL sidecar accepts Windows-path workspaces. Creating a C:/ workspace on a WSL connection makes the server realPath('C:/') → ENOENT, the event stream dies, chat is impossible. Suggest validating path reachability per server type, or auto-translating to /mnt/c/....

  6. Custom server entry cannot be deleted when state-file writes fail (bug 1) and tabs/selection still reference it. Needs cascade cleanup (tabs/selection/notification/workspace bindings) plus a conflict prompt.

  7. (Minor, already healed in 1.18.3) A July desktop build called SessionContextEpoch.requestReplacement referencing column replacement_seq, which its own bundled migration (20260622142730_simplify_session_context_epoch) had already dropped → runtime "no such column". Flagging as a release-consistency check suggestion.

User-side repair (completed; app fully usable again): replayed event logs to rebuild projections, fixed stale paths in both DBs, repaired the state file via lenient parse + canonical re-serialization, merged the Windows DB into the WSL DB with path translation (C:/→/mnt/c/, E:/→/mnt/e/, D:/→/mnt/d/), and removed the dead server entry with all its references. Full step-by-step write-up with evidence attached.


### Plugins

_No response_

### OpenCode version

Desktop 1.18.3 (Electron 42.3.3); WSL server/sidecar 1.18.1; CLI 1.17.18 

### Steps to reproduce

1. State file corruption: insert an unescaped raw newline inside a string value in %APPDATA%\ai.opencode.desktop\opencode.global.dat (simulating an unescaped error message) → launch the desktop app → renderer throws "Bad control character in string literal" on every store-set; UI state never persists; sending messages fails.
2. Dangling last-session pointer: with "last session" = session X in server A's DB only, switch to server B whose DB lacks session X → white screen "Session not found: X". Similarly, delete a custom server still referenced by home.selection → restart → white screen "Notification server not found".
3. Stale path: have a session row whose session.path is an absolute path of a since-deleted directory (e.g. moved project) → open the session (browsable) → send a message → server joins worktree+path, realPath fails → "cannot get session".
4. WSL workspace: connect to a WSL server, create a workspace at C:/ (any Windows path) → server logs PlatformError NotFound realPath, event stream disconnects, cannot chat.

(Item 2 in Description — missing projections — was observed on live data; we do not know which build deleted the rows. The event logs are intact and contain no tombstone events.)

### Screenshot and/or share link

[opencode-bug-report-20260717-en.md](https://github.com/user-attachments/files/30098091/opencode-bug-report-20260717-en.md)

[opencode-debug-20260716T155136.zip](https://github.com/user-attachments/files/30098110/opencode-debug-20260716T155136.zip)

### Operating System

Windows 11 (desktop); Ubuntu-24.04 via WSL2 mirrored networking (server) 

### Terminal

Desktop app (Electron); Windows Terminal for CLI usage

Activity

  1. github-actions commented on Jul 16, 2026

    @github-actions
    Contributor

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

  2. robertn702 commented on Jul 19, 2026

    @robertn702

    Another data point, this time on macOS (Desktop 1.18.3) — so not WSL-specific. Same failure family: opencode.global.dat + stale absolute paths.

    What happened here: a Superset worktree subfolder (/Users/robert/.superset/worktrees/540f8918-…/test-setup) was deleted out from under the app. The app kept it in the server key of opencode.global.dat:

    "projects": { "local": [
      { "worktree": "…/test-setup", "expanded": true },
      { "worktree": "/Users/robert/Documents/Default Project", "expanded": true }
    ]},
    "lastProject": { "local": "…/test-setup" }

    Symptoms:

    • Every launch: sidecar realpath(lastProject) inside Server.listen → PlatformError: NotFound … ENOENT; /api/reference?directory=<deleted> → HTTP 500.
    • Every send in the affected sessions: prompt_async failed with Cause([Die(PlatformError: NotFound: FileSystem.realPath (…))]) — and no error in the chat UI. The message appears to send; the session never responds.
    • Renderer console stays clean (only ResizeObserver noise). The failure is only visible in ~/.local/share/opencode/log/opencode.log and the app's Chromium netlog (…/T/ai.opencode.desktop.scoped_dir./event_file_.json`).
    • The UI derives the displayed project from the git root, so the dead worktree path is invisible — it looks like "the main project is broken", and selecting the main worktree doesn't help because new sessions were still being created against lastProject`.

    Strong +1 on the repair-path suggestions: in this state there is no in-app way to fix or even diagnose it — I had to inspect the netlog and sqlite DBs to find the binding. Boot-time validation of projects[].worktree / lastProject (drop-or-flag missing) plus an in-chat error when prompt_async dies would have made this a 30-second fix.

  3. wkkxkc commented on Sep 13, 2026

    @wkkxkc

    I think I found another way to hit the corrupted global store problem described here.

    On the affected Windows machine, opencode.global.dat started with a UTF-8 BOM (EF BB BF). The rest of the file was valid JSON, but electron-store passes the decoded U+FEFF straight to JSON.parse, so the store could no longer be read.

    This was hard to notice because store-get catches the error and returns null, while store-set rejects. In my case the model visibility toggles worked until restart, and renderer.log showed the same SyntaxError for every write.

    Removing only the BOM fixed it. The existing values loaded again, and the next write rewrote the file without the BOM.

    I checked the current dev branch at 95daf906: store.ts still uses the default deserializer, and the store-get / store-set behavior is unchanged. I also couldn't find an existing report or PR for this specific BOM case.

    Would a small PR that strips a leading BOM during deserialization and adds a regression test be welcome? I can leave the broader backup/reset behavior for malformed JSON as a separate change.

  4. 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

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