Repository navigation
Description
Summary
On OpenCode Desktop 2.2.2 (Windows), the Browser entry disappeared from the session side panel's + (new tab) launcher after updating from 2.2.1. Only Review, Terminal, and Open file remain, and there is no launcher left that can open a browser pane for the first time.
The launcher is registered only when attached(session) is already true, so once the pane is not attached there is no path back to it through the UI.
Environment
- opencode version: Desktop app
2.2.2(bundled CLI2.2.2). A separateopencodeonPATHreports2.0.32. - OS:
Microsoft Windows [Version 10.0.26300.9550](win32 x64) - Terminal: OpenCode Desktop (Electron app,
packaged: true);TERM=xterm-256color,TERM_PROGRAMunset - Shell:
C:\WINDOWS\system32\cmd.exe - Install/channel: OpenCode Desktop, channel
latest, auto-updater, packaged build at%LOCALAPPDATA%\Programs\ai.opencode.desktop - Active plugins:
superpowers@git+https://github.com/obra/superpowers.git(2ce8aa1),rtk(local~/.config/opencode/plugins/rtk.ts). MCP servers:playwright,dev-workflow,clinic-helper.
Reproduction
- On OpenCode Desktop 2.2.1, open a session and open the browser pane (or let it open from a
http://localhost:...link in a message). - Update the app to 2.2.2 and restart. The main log records the server restart on the version change:
v2 CLI background service starting { reason: 'version-mismatch', previousVersion: '2.2.1' } - Open a session and click + in the session side panel to open the new-tab / launcher list.
- Observe the launcher list.
Expected Behavior
Browser appears in the side panel + launcher so the browser pane can be opened, as it did on 2.2.1.
Actual Behavior
The launcher list only contains Review, Terminal, and Open file. There is no Browser entry, no browser tab, and no obvious way to open a browser pane from the UI.
Additional Context
Cause: the launcher is gated on attached()
packages/gui-plugins/src/browser/renderer.tsx registers the launcher only when the pane is already attached:
ctx.add(MenuItem, (): MenuItem | undefined => {
const view = sessions.current()
const value = model()
// Only once the desktop's pane answers.
if (!view || !value?.available(view) || !value.attached(view)) return undefined
// A launcher of the side panel's new tab view, between Review and Terminal.
return {
menu: "session.panel",
id: "open",
...
}
})And attached() requires an existing registration or existing browser state — packages/gui-plugins/src/browser/model.ts:358:
const attached = (session: Session) => {
const value = attachment(session)
return value?.registration !== undefined || !!value?.browser
}So the launcher is a function of "a browser pane is already attached", but its run is open(session) — the action that opens the browser pane in the first place. When the pane is not attached (fresh app start, server restart on update, or a failed registration), the launcher can never render, and the user has no launcher to attach it again. The Open browser command and its keybind still work, which confirms the pane itself is fine — only the discoverable entry point is gone.
Contributing: the unsupported flag is sticky for the app's lifetime
model.ts:225 sets a permanent per-server flag on a single failed registration, and nothing ever clears it:
change: (next, mirror, native) => {
if (next.error === "browser.pane.unsupported") {
setState("unsupported", ref.server.id, true)
return close(id)
}available() then returns false forever (model.ts:374), which also disables the Open browser command:
const available = (session: SessionRef) =>
!state.unsupported[session.server.id] && !!session.id && session.server.compatible && !layout.narrow()connection.ts:173 likewise latches blocked = true for browser.pane.unsupported and browser.pane.replaced, with no reset path. A server restart during an app update is exactly the situation where browser.pane.replaced can fire, after which the browser pane never comes back until the whole app is restarted.
Workaround
- Command palette (
Ctrl+K) → Open browser, orCtrl+Alt+B. Once the pane opens, the launcher entry reappears for that session. - Or fully quit and relaunch OpenCode Desktop, which resets the sticky
unsupportedstate.
Suggested fixes
- Register the side-panel launcher on
available(session)only, and letrunperform the first attach (drop theattached()requirement), or keep the launcher visible butenabled: falseuntil attached. - Clear
state.unsupported[server.id]when the server reconnects, its version changes, or the pane's Ipc comes back, instead of latching it for the app's lifetime.
Notes
- The browser pane itself is functional; this is a discoverability regression in the launcher, not a broken pane.
server.compatibleistrueand/api/inforeports2.2.2on the desktop's own server (http://127.0.0.1:28894), so this is not a version-mismatch gate.- Unrelated but observed in the same session: the
playwrightMCP server exits with code 1 after a few minutes (mcp transport error ... "MCP server process exited with code 1"). Happy to file that separately if useful.
Activity
opencodejr commentedon Oct 30, 2026
Thanks for the detailed report and analysis!
I think this is a duplicate of #60369. It reports the same thing: on OpenCode Desktop 2.2.2 for Windows, the Browser entry disappears from the side panel's + menu right after the update, leaving only Review, Terminal and Open file. The cause found there is that the browser part of the 2.2.2 desktop build fails to load. It shows up in
main.logasscope finalizer failed { scope: 'browser', error: "SyntaxError: Identifier 'n' has already been declared" ... }. A fix (#60430) has been merged. It would help to check whether your%APPDATA%\ai.opencode.desktop\logs\...\main.loghas that error.Your analysis of the
attached()gating and the stickyunsupported/replacedstate is already tracked in #60023, which proposes the same fixes. PR #60123 is open for it.Possible duplicates and related issues, ordered from most to least likely:
available() && attached(), andunsupported/replacedstay set until the app restarts (fix PR fix(browser): keep launcher available while pane is detached #60123)The bot will close this issue as a duplicate in 1 day unless you reply explaining how your problem is different. For example, if your
main.loghas noSyntaxErrorand only the launcher behaviour from #60023 applies. TheplaywrightMCP server exiting with code 1 is unrelated, so a separate issue for it would be welcome.mahatmamahardhikach commentedon Oct 30, 2026
Correction: this is #60369. My earlier analysis in this comment was wrong, and I can now prove the chunk itself is broken.
The decisive test
I ran the same check that #60430 adds to the build (
verifyBundles: parse every emittedout/mainchunk withvm.SourceTextModule) directly against the installedresources/app.asaron this machine:Exactly one chunk out of 650 fails to parse, and it is the browser pane chunk — the same
Identifier 'n' has already been declaredas #60369. No crash needed to see it.Why my
main.logis clean (and why that misled me)pane-*.jsis imported lazily, on the first attach:On this machine no attach is ever attempted, so the chunk is never imported, so it never throws, so
scope finalizer failednever appears.main.logfor both 2.2.2 launches contains only updater lines;app startingcount is 1 per log folder (no relaunch), and Crashpad is empty. That absence is not evidence of health — it is evidence the chunk was never reached.This matches what @RonnyWu noted in #60433: "the failure looks one-shot, on the first attach attempt after launch."
What still holds, and what I retract
Still true, but irrelevant to the bug — it only proves registration, not behaviour:
Retracted: my claim that "the browser pane itself is healthy" because
layout.sessionTabscontainsbrowser:tab_*entries. Those rows are stale — the newest write toname='plugin.browser'indrafts.sqliteis2026-10-30T01:01:21Z, which is before the first 2.2.2 launch at2026-10-30T01:06:51Z. The pane has written nothing since 2.2.2 was installed. Interpreting persisted tab layout as a live pane was a mistake.Also retracted: the
open()/ "no path to a first tab" theory. In the shipped bundleopen()does sendtabs.open; it fails earlier because there is no registration to send it over.Summary
pane-*.jschunk that cannot be parsed.resources/app.asar→out/main/pane-*.js, or just check whetherplugin.browserhas written anything since the 2.2.2 install time.Hona commentedon Oct 30, 2026
Fixed in 2.2.3 by #60430.
The desktop main-process bundle declared
requiretwice, which broke the in-app browser and itsbrowser.*tools.Please update to 2.2.3. In the desktop app, use Check for Updates, or install it from the release page. If the browser pane still doesn't appear afterwards, please reopen this issue with your
main.logfrom the logs folder.opencodejr commentedon Oct 31, 2026
We haven't heard back, so I'm closing this as a duplicate of #60369. That issue covers the missing Browser entry on Desktop 2.2.2 for Windows after the update, and its fix (#60430) has been merged. Your analysis of how
attached()hides the launcher and why theunsupported/replacedstate persists until restart is tracked in #60023, with PR #60123 open for it. Please follow those issues for updates.If your
main.loghas noSyntaxError: Identifier 'n' has already been declaredand the problem looks different, comment here and we can reopen. Thanks again for the detailed report!phoenixgao commentedon Nov 10, 2026
Updated from 2.2.5 to 2.2.7, the browser panel is gone again @Hona
ThomasCro33 commentedon Nov 11, 2026
It is gone, and it breaks my main workflow completely, please restore it as soon as possible.
jlKampos commentedon Nov 12, 2026
reinstalling fixes it
https://opencode.ai/product