Summary
On a clean install/upgrade, browse connect (headed) fails with Executable doesn't exist at .../ms-playwright/chromium-1208/... even though ./setup reported success and headless browse works fine. Root cause: the version of Playwright that ./setup uses to install browsers is resolved at runtime (latest) and downloads a different Chromium revision than the one embedded in the compiled browse binary, and the post-install verification only launches headless, so the mismatch is never caught.
Environment
- gstack
1.55.0.0 (also reproduced on 1.28.0.0 before upgrading)
- macOS arm64, Node v26.0.0, Bun 1.3.11
- Install type: global-git (
~/.claude/skills/gstack)
What happens
$ browse connect
Launching headed Chromium with extension + terminal agent...
[browse] Connect failed: Server failed to start:
persistentContext: Executable doesn't exist at
~/Library/Caches/ms-playwright/chromium-1208/chrome-mac-arm64/Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing
at async launchHeaded (browse/src/browser-manager.ts:557:35)
at async start (browse/src/server.ts:2938:28)
Headless browse (e.g. /qa headless, goto, snapshot) works perfectly the whole time.
Playwright cache after a fresh ./setup:
chromium_headless_shell-1208 <- present (why headless works)
chromium_headless_shell-1223
chromium-1223 <- full build, WRONG revision
ffmpeg-1011
# chromium-1208 (full) is MISSING -> headed fails
Root cause
- The compiled
browse binary (bun --compile) embeds a pinned Playwright that resolves Chromium revision 1208 (Chrome for Testing 145.0.7632.6, Playwright 1.58.2).
setup installs browsers with bunx playwright install chromium (setup ~line 483), which resolves latest Playwright at runtime (currently 1.60.0 -> revision 1223). So it downloads the wrong full build.
ensure_playwright_browser() (setup ~line 252) verifies with a headless launch:
bun --eval 'import { chromium } from "playwright"; const browser = await chromium.launch(); await browser.close();'
This passes because chromium_headless_shell-* is present, so the missing full build (needed by launchHeaded) is never detected.
Net: setup's installer Playwright and the compiled binary's Playwright are not the same version, and the verify step only exercises headless. Headed users are broken on a "successful" install.
Workaround (confirmed fix)
Install the full Chromium at the revision the compiled binary pins:
bunx playwright@1.58.2 install chromium # downloads chromium-1208 full (~162MB)
browse connect # -> Mode: headed ✅
Suggested fix
- Install browsers using the same Playwright version embedded in the compiled
browse binary, not a runtime-resolved latest. e.g. pin playwright@<bundled-version> in the setup install step, or expose browse install-browsers that shells out to the binary's own embedded Playwright so install and runtime can never drift.
- Make
ensure_playwright_browser() launch headed (or assert the full Chrome-for-Testing executable path exists), so a missing full build fails setup instead of being masked by the cached headless shell.
Summary
On a clean install/upgrade,
browse connect(headed) fails withExecutable doesn't exist at .../ms-playwright/chromium-1208/...even though./setupreported success and headlessbrowseworks fine. Root cause: the version of Playwright that./setupuses to install browsers is resolved at runtime (latest) and downloads a different Chromium revision than the one embedded in the compiledbrowsebinary, and the post-install verification only launches headless, so the mismatch is never caught.Environment
1.55.0.0(also reproduced on1.28.0.0before upgrading)~/.claude/skills/gstack)What happens
Headless
browse(e.g./qaheadless,goto,snapshot) works perfectly the whole time.Playwright cache after a fresh
./setup:Root cause
browsebinary (bun--compile) embeds a pinned Playwright that resolves Chromium revision 1208 (Chrome for Testing 145.0.7632.6, Playwright 1.58.2).setupinstalls browsers withbunx playwright install chromium(setup ~line 483), which resolves latest Playwright at runtime (currently 1.60.0 -> revision 1223). So it downloads the wrong full build.ensure_playwright_browser()(setup ~line 252) verifies with a headless launch:bun --eval 'import { chromium } from "playwright"; const browser = await chromium.launch(); await browser.close();'chromium_headless_shell-*is present, so the missing full build (needed bylaunchHeaded) is never detected.Net: setup's installer Playwright and the compiled binary's Playwright are not the same version, and the verify step only exercises headless. Headed users are broken on a "successful" install.
Workaround (confirmed fix)
Install the full Chromium at the revision the compiled binary pins:
Suggested fix
browsebinary, not a runtime-resolved latest. e.g. pinplaywright@<bundled-version>in the setup install step, or exposebrowse install-browsersthat shells out to the binary's own embedded Playwright so install and runtime can never drift.ensure_playwright_browser()launch headed (or assert the full Chrome-for-Testing executable path exists), so a missing full build fails setup instead of being masked by the cached headless shell.