Skip to content

global project row icon_url permanently polluted — all workspaces display wrong icon #39488

Closed as not planned

Description

@Jasper-111

Description

The global row (id='global', worktree='/') in the project table acts as the fallback data source for all workspaces. Its icon_url field was found to contain a base64-encoded .ico file from a specific project directory. This causes every project in the sidebar to display the same cookie icon, overriding both default colored avatars and custom icons.

Plugins

None

OpenCode version

v1.17.8 (Desktop) and v1.17.8 (CLI)

Steps to reproduce

Have a project directory containing an img/icon.ico (or favicon.ico).

Open it in OpenCode Desktop.

Observe: after some interaction (possibly Edit Project or auto-discovery), the icon leaks into the global row.

All other projects now display this icon instead of their own.

Screenshot and/or share link

Image Image

Operating System

Windows 10 Home (10.0.19045 Build 19045), Lenovo LAPTOP-CSJ6J9R1

Terminal

Windows Terminal

Activity

  1. Jasper-111 commented on Jul 29, 2026

    @Jasper-111
    Author

    Title: [BUG] global project row icon_url permanently polluted — all workspaces display wrong icon

    Environment

    • OS: Windows 10 Home (10.0.19045 Build 19045), Lenovo LAPTOP-CSJ6J9R1
    • OpenCode Desktop: v1.17.8 (installed via @opencode-aidesktop at %LOCALAPPDATA%\Programs\)
    • CLI: v1.17.8 (npm global)
    • DB: %USERPROFILE%\.local\share\opencode\opencode.db (SQLite)
    • Workspace files: %APPDATA%\ai.opencode.desktop\opencode.workspace.*.dat (electron-store JSON)

    Summary

    The global row (id='global', worktree='/') in the project table acts as the fallback data source for all workspaces that lack their own icon metadata. Its icon_url field was found to contain a base64-encoded .ico file from a specific project directory (E:\04_archive\cookieclicker-gh-pages\img\icon.ico). This causes every project in the sidebar to display the same cookie icon, overriding both default colored avatars and custom icons set via Edit Project.

    Reproduction

    1. Have a project directory containing an img/icon.ico (or icon.png, favicon.ico)
    2. Open it in OpenCode Desktop
    3. Observe: after some interaction (possibly Edit Project or auto-discovery), the icon leaks into the global row
    4. All other projects now display this icon instead of their own

    Root Cause Analysis

    Data flow: getProjectAvatarSource() in packages/app/src/pages/layout/helpers.ts:96-102 resolves icons with this priority:

    if (icon?.override) return icon.override   // from workspace:icon (electron-store)
    if (icon?.color) return undefined          // falls back to colored avatar
    return icon?.url                            // from project.icon_url (SQLite) ← POLLUTED

    When no specific project has icon_color or icon_url_override set, the rendering falls through to the project table's icon_url. The global row serves as catch-all — so its icon_url affects every project without explicit icon data.

    Pre-fix DB state:

    SELECT id, worktree, icon_url, icon_color FROM project WHERE id='global';
    -- global | / | data:image/vnd.microsoft.icon;base64,AAABAAEAEBAQAAAAAA... | NULL

    How global got polluted: The exact entry point is likely icon auto-detection. When OpenCode discovers icon files in project directories and stores them to the project table, a path mismatch (e.g., zero-width space in 04_archive\u200B\cookieclicker-gh-pages) could cause the icon to be written against the global fallback row instead of a project-specific row.

    Secondary Bug: Edit Project Save Path

    Verified from source and local data: the save.mutationFn() in packages/app/src/components/edit-project.ts:71-95 has two code paths:

    if (props.project.id && props.project.id !== "global") {
      // Path A: Writes to project table + workspace:icon (sidebars reads BOTH)
      await serverCtx().sdk.client.project.update({...});
      serverCtx().sync.project.icon(worktree, iconOverride);
    } else {
      // Path B: Writes ONLY to workspace:project (sidebar NEVER reads this for icons)
      serverCtx().sync.project.meta(worktree, {name, icon: {color, override}});
    }

    The sidebar reads childStore.icon (workspace:icon key) and project.icon_url (SQLite table), but Path B writes to workspace:project — making any Edit Project save on local projects silently lost.

    Confirmed locally: workspace files contain workspace:project entries with icon data, but the rendering code never reads from this key for icon display.

    Database State (12 projects, all affected)

    id                                    | worktree                                 | icon_url | icon_color
    global                                | /                                        | POLLUTED | NULL
    ef42ab23f99f...                       | C:/Users/Lenovo/Documents/Obsidian Vault | NULL     | cyan
    3ea29ca39f1e...                       | E:/01_project/burn_coinjoin              | NULL     | mint
    93ac7b952000...                       | E:/04_archive/joinmarket-clientserver    | NULL     | pink
    bc3f3bdd6992...                       | E:/01_project/NotionJunction             | NULL     | orange
    fb655ede9f83...                       | E:/04_archive/kittensgame-master         | NULL     | purple
    6a93883275f4...                       | E:/01_project/MemoryMomentum             | NULL     | orange
    d60bc3734616...                       | E:/04_archive/AutoDesign-main             | NULL     | pink
    8e93b52d71b5...                       | E:/01_project/Lumos                      | NULL     | yellow
    693549fa1b71...                       | E:/04_archive/jam                        | NULL     | mint
    fe4c2928bcc8...                       | E:/03_infra/tether                       | NULL     | lime
    46aec917f2db...                       | E:/01_project/bdk-lab                    | NULL     | orange
    4799e59f6f1e...                       | E:/04_archive/bitchat                    | NULL     | cyan
    

    Notice: no project has icon_url or icon_url_override set. Only icon_color is populated. The global row's icon_url is the sole source of the cookie icon appearing everywhere.

    Local Fix Applied

    UPDATE project SET icon_url = NULL WHERE id = 'global';

    All projects immediately show their correct colored avatars after restart.

    Workaround for Affected Users

    -- 1. Close OpenCode Desktop
    -- 2. Open opencode.db with sqlite3:
    sqlite3 "%USERPROFILE%\.local\share\opencode\opencode.db"
    -- 3. Run:
    UPDATE project SET icon_url = NULL WHERE id = 'global';
    -- 4. Restart OpenCode Desktop

    Proposed Code-Level Fixes

    1. Guard global row: Add assertion in any icon-writing code path: if (projectId === "global") return — the global row should NEVER receive a project-specific icon URL
    2. Add fallback in enrich(): layout.tsx:224 should also check childStore.projectMeta?.icon?.override as a fallback for projects without workspace:icon entries
    3. Data migration: On app startup, sanitize: UPDATE project SET icon_url = NULL WHERE id = 'global' AND icon_url IS NOT NULL
    4. Unify save path: edit-project.ts should call both project.icon() and project.meta() regardless of project ID

    Related

  2. caleblea commented on Aug 5, 2026

    @caleblea

    Confirming this on the latest desktop release (v1.18.13, macOS) — still reproducible.

    Empirical data from my machine:

    • The project table in ~/.local/share/opencode/opencode.db has a row with id='global' / worktree='/' holding a polluted icon_url (base64 data URL).
    • The stored bytes are byte-for-byte identical to my project's frontend/public/favicon.ico (456 bytes). So the favicon auto-discovery (the desktop app always sets OPENCODE_EXPERIMENTAL_ICON_DISCOVERY=true for its bundled server) wrote the discovered icon into the global fallback row instead of the project's own row.
    • 25+ sessions on my machine have project_id='global', so every project/session that resolves to the global row renders that same favicon — every project in the sidebar shows the same photo.
    • The originating project itself displays correctly because it also has icon_color set (color wins over url in getProjectAvatarSource), which makes the leak look exactly like "one project's photo applied to all others".

    Workaround that works (after quitting the desktop app):

    UPDATE project SET icon_url = NULL, icon_url_override = NULL WHERE id = 'global';

    Purely cosmetic, but it affects every workspace and is quite confusing. Happy to provide more logs/screenshots if helpful.

  3. github-actions commented on Oct 4, 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