Skip to content

tui: cannot remove stale projects from /open list; desktop crashes on non-existent project #49442

Closed as duplicate

Description

@XXLxhPLMM

Description

Two related issues around handling non-existent project directories:

TUI — /open and /project commands show stale projects that can't be removed:

When a project directory is moved or deleted, the /open and /project commands still list it as a previously opened project. There is no way to remove stale entries. If the user selects one, the session fails or hangs.

Desktop — Settings > Projects shows non-existent projects, and opening them crashes the app:

In the desktop app, the Settings > Projects panel lists previously opened projects. If a project directory has been moved or deleted, it still appears in the list. When the user tries to open it, the app throws:

ClientError: UnexpectedStatus
    at i (oc://renderer/assets/health-BdaR9NAA.js:1:41042)

原因:
{
  status: 500
}

The desktop app becomes unresponsive and must be manually restarted.

Steps to reproduce

TUI:

  1. Open a project in TUI (/open or startup)
  2. Move or delete that project directory from disk
  3. Run /open or /project again — the old project still appears in the list
  4. There is no option to remove it from the list

Desktop:

  1. Open a project in the desktop app
  2. Move or delete that project directory from disk
  3. Go to Settings > Projects — the old project still appears
  4. Try to open it — the app crashes with ClientError: UnexpectedStatus (status: 500) and must be restarted

Expected Behavior

  • TUI: /open and /project should detect stale (non-existent) project entries and either remove them automatically or provide a way to delete them from the list
  • Desktop: Settings > Projects should detect stale entries and either remove them or show a clear error message ("Project directory not found") instead of crashing the app

Actual Behavior

  • TUI: Stale projects persist in /open and /project lists with no way to clean them up
  • Desktop: Settings > Projects shows stale entries; opening one crashes the app with a 500 error requiring a full restart

Additional Context

  • opencode version: 2.0.3
  • OS: Windows_NT 10.0.26200 (win32 x64)
  • Terminal: xterm-256color (TUI mode)
  • Shell: cmd.exe
  • Install/channel: npm global, latest
  • Active plugins: None
  • This is a common scenario when reorganizing project directories or migrating between machines

Activity

  1. github-actions commented on Sep 17, 2026

    @github-actions
    Contributor

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

  2. XXLxhPLMM commented on Sep 17, 2026

    @XXLxhPLMM
    Author

    Thanks for flagging these. I've encountered all three scenarios described in those issues:

    This issue consolidates all three into one report since they share the same root cause: opencode doesn't validate whether a project directory still exists, and provides no way for users to clean up stale entries from either TUI or desktop. Happy to close this in favor of tracking them separately if that's preferred.

  3. XXLxhPLMM commented on Sep 17, 2026

    @XXLxhPLMM
    Author

    Update: I've been manually removing stale entries from the data files to clean up the project list. This works but is not user-friendly.

    Would it be possible to add a command (e.g., /project remove <name> in TUI, or a delete button in Desktop Settings > Projects) that lets users remove project entries directly from the UI? I'd be happy to submit a PR for this if the approach sounds reasonable.

  4. XXLxhPLMM commented on Sep 17, 2026

    @XXLxhPLMM
    Author

    Here's what I had in mind for the implementation:

    1. TUI command palette — shortcut key for stale project cleanup

    In /open and /project panels, add a快捷键 (e.g., d or Delete) to remove a selected project entry. This would work like a quick inline delete without leaving the command palette.

    2. CLI subcommand — opencode project

    Add a new CLI command with subcommands:

    Command Description
    opencode project list List all registered projects
    opencode project del <name> Remove a project entry from the list
    opencode project delsession <name> Clear all sessions associated with a project

    This gives both TUI and CLI users a way to manage projects without manually editing data files.

    Happy to submit a PR covering both the TUI shortcut and the CLI subcommands if this approach is acceptable.

  5. Drewlius commented on Oct 5, 2026

    @Drewlius

    DISCLAIMER THIS WAS GENERATED BY OPENCODE/BIG-PICKLE USING THE BUILT IN @report SKILL**

    Adding a repro path that isn't in the original description: the trigger here was renaming a project in the desktop project viewer, not moving or deleting the directory. Worth separating because the rename makes the failure fatal, where merely having a stale entry is only survivable.

    What I did

    1. Opened a git project in opencode-desktop so it appeared in the project viewer.
    2. Renamed the directory on disk in the file browser (superMemory_Redux_OpenCode → superMemory-Redux_OpenCode). The old entry stayed in the viewer, now pointing at a path that no longer exists.
    3. Opened the stale entry. No crash, but no model could be selected — the model list failed to load.
    4. Opened the renamed directory. Models loaded normally.
    5. Renamed the stale entry in the project viewer to match the new directory name.
    6. opencode-desktop immediately showed an HTTP 500 error screen and never rendered again, on every subsequent launch.

    Step 3 is the interesting part: the stale project was already returning 500 before the rename (/api/model failing, surfaced as an unusable model picker). The rename didn't create the fault, it changed which client code path hit it — from a per-request failure you can navigate away from, to a bootstrap failure the renderer treats as unrecoverable.

    Evidence

    The rename and the first fatal error are 8 seconds apart, with no process restart in between:

    11:21:07.496  rename persisted (drafts.sqlite, key workspace:project, value {"name":"superMemory-Redux_OpenCode"})
    11:21:15.288  first "fatal renderer error" in the same running session
    

    Every subsequent launch reproduced it identically: 11:21:19, 11:21:39, 11:21:48, 11:22:25, 11:23:58, 11:24:57, 11:25:57, 11:35:08.

    Renderer log:

    [error] (renderer) fatal renderer error {
      error: 'ClientError: UnexpectedStatus: 500\n    at i (oc://renderer/assets/main-UEFaZZZo.js:30:22384)\n\n────────────────────────────────────────\nCaused by:\n{\n  "status": 500\n}',
      url: 'oc://renderer/index.html',
      version: '2.0.22',
      platform: 'desktop',
      os: 'linux'
    }
    

    Confirmed the 500 comes from the missing directory by querying the running sidecar directly via the x-opencode-directory header:

    x-opencode-directory: /home/user/repos/superMemory_Redux_OpenCode/   -> 500
    x-opencode-directory: /home/user/repos/superMemory-Redux_OpenCode/  -> 200
    

    Two details that may matter for the fix

    lastProject was not repointed. In drafts.sqlite, table state, key server, the lastProject field was last written at 11:20:41 — before the rename — and already pointed at the valid path. So the rename did not make the stale directory the active project. The only value it persisted was a display name, on the stale entry.

    After the rename, two entries share the display name superMemory-Redux_OpenCode while their worktree paths differ:

    {
      "projects": {
        "local": [
          {"worktree": "/home/user/repos/superMemory-Redux_OpenCode/", "expanded": true},
          {"worktree": "/home/user/repos/superMemory_Redux_OpenCode/",  "expanded": true}
        ]
      },
      "lastProject": {"local": "/home/user/repos/superMemory-Redux_OpenCode/"}
    }

    That collision is my leading hypothesis for why the rename turns a survivable 500 into a fatal one — something resolves by display name and lands on the stale path. I could not confirm it. I only had the packaged bundle at /usr/lib/opencode-desktop, not the desktop source, so the mechanism inside the rename handler is unverified. The timestamps establish the trigger; the mechanism is inference.

    Confirming the lockout, and the workaround

    The app crashes before the project viewer can be reached, so there is no in-app way to remove the offending entry — which is the same dead end described in the TUI half of this issue, except here it blocks recovery entirely rather than just cleanup.

    With the app closed, removing the stale entry from the server key in drafts.sqlite restores startup. Verified: PRAGMA integrity_check returns ok, and the app launches.

    One caveat that cuts against the collision theory: that same project list still contains three other paths that don't exist on disk, and the app launches fine with them present. So bootstrap only appears to fetch config for the active project, not every entry — which doesn't fully explain how the stale entry was reached during bootstrap at all. I'd rather flag that gap than guess at it.

    Environment

    • opencode 2.0.23 (CLI); opencode-desktop 2.0.22, bundled sidecar CLI 2.0.22
    • Linux, KDE Plasma, packaged release at /usr/lib/opencode-desktop, sidecar on 127.0.0.1:49374
    • Local plugin ~/.config/opencode/plugins/superMemory-Redux_OpenCode.js, plus opencode-wakatime

    Suggested additions to the expected behavior

    • Renaming a project should not be able to leave the app unable to start. A display-name change shouldn't alter which directory gets resolved.
    • The project viewer needs to allow removing an entry whose directory is gone, independent of the TUI /open fix above.
    • If two projects can end up with the same display name, name-based resolution needs to be made unambiguous.

    DISCLAIMER THIS WAS GENERATED BY OPENCODE/BIG-PICKLE USING THE BUILT IN @report SKILL**

  6. renengade commented on Oct 11, 2026

    @renengade

    I found an additional related behavior: every time the client resolves locations for these stale/dead projects (where the directory no longer exists), time_active still gets bumped even when location resolution returns 404.

    This means these dead projects never age out of the recent project list (Ctrl+O). Instead, they keep jumping back to the top of the list every time the recent projects menu is opened.

    This is a separate aggravating factor beyond the projects simply persisting in the database.

  7. neriousy commented on Oct 23, 2026

    @neriousy
    Member

    Closing this consolidation as a split duplicate. Project removal and TUI/CLI cleanup are tracked in #51197; Desktop missing/inaccessible-folder failures are tracked in #50951. The proposed cleanup commands, fatal-rename reproduction, and time_active details have been transferred to the appropriate issues.

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