Background-mode browser launch fails, and concurrent profiles surface a cryptic error (CloakBrowser free-tier session cap)
Summary
Two related problems make multi-profile / adapter-eval runs unusable, both surfacing as the same cryptic error:
page.goto: Target page, context or browser has been closed
After tracing it end to end, the webcmd daemon and profile multiplexing are correct — the failures originate in the CloakBrowser launch layer:
- Background mode (default) self-terminates on launch. A single background CloakBrowser instance exits ~250–320ms after the daemon connects, even with only one profile and nothing else running. Every command that then does a
page.goto fails with Target page, context or browser has been closed.
- Concurrent profiles hit CloakBrowser's free-tier 1-session cap. Launching a second profile's browser while a first is alive makes the second exit with code 76. This is a CloakBrowser licensing limit, not a webcmd bug — but webcmd reports it as the same opaque "target closed" error with no hint that it's a concurrency/licensing issue.
The net effect: the twitter adapter eval (webcmd-adapter-eval, actor/peer profiles) fails on every step, and the error message points nowhere useful.
Environment
- webcmd:
v0.5.2
- cloakbrowser:
0.4.5
- Chromium binary:
chromium-150.0.7871.114.3-pro
- OS: macOS (Apple Silicon)
- CloakBrowser license tier: Free (no
CLOAKBROWSER_LICENSE_KEY / license.key)
Reproduction
Case 1 — background mode, single profile
webcmd daemon restart
webcmd --profile actor-profile twitter timeline --limit 5
Result:
ok: false
error:
code: COMMAND_EXEC
message: "Pre-navigation to https://x.com failed: page.goto: Target page, context or browser has been closed ..."
Case 2 — two profiles concurrently (foreground)
export WEBCMD_WINDOW=foreground
webcmd --profile peer-profile twitter whoami # keeps peer's browser alive
webcmd --profile actor-profile twitter login # second live browser
The second launch exits 76 and page.goto fails.
Evidence (daemon instrumentation)
With logging added at the launch and context-close points, plus DEBUG=pw:browser:
Background, single profile — browser disconnects on its own ~320ms after connect:
[cloak-debug] bg connected port=59315 dir=.../peer-profile at 03:40:08.380Z
[cloak-debug] launched profile=peer-profile mode=background active=[peer-profile] 03:40:08.385Z
[cloak-debug] context 'close' fired profile=peer-profile pages=1 at 03:40:08.706Z
[cloak-debug] bg browser DISCONNECTED dir=.../peer-profile at 03:40:08.706Z
context 'close' and bg browser DISCONNECTED fire at the same timestamp — nothing in webcmd closed it; the Chromium process exited by itself. ps shows zero cloakbrowser processes before the run and none lingering after.
Foreground, second concurrent profile — exit code 76:
pw:browser <launched> pid=60564 (peer, survives)
pw:browser <launched> pid=60634 (actor, launched while peer alive)
[cloak-debug] launched profile=actor-profile mode=foreground active=[peer-profile,actor-profile]
pw:browser [pid=60634] <process did exit: exitCode=76, signal=null>
Same profile dir works fine when launched alone in foreground; it only dies when a second browser is already live → consistent with CloakBrowser free-tier "1 concurrent session."
Root cause
- Background launch (
launchDarwinBackgroundPersistentContext, src/browser/runtime/local-cloak/darwin-background-launch.ts) starts Chromium via /usr/bin/open -g -n … and attaches over CDP. The -g (hidden, no-window) LaunchServices instance appears to be sudden-terminated by macOS shortly after launch. The foreground path (chromium.launchPersistentContext, Playwright-managed) keeps a single browser alive, which is why WEBCMD_WINDOW=foreground "works" for one profile.
- Concurrency is capped by CloakBrowser's license tier (free = 1 session); the second instance exits 76. webcmd multiplexes profiles correctly, but cannot exceed the license cap.
Impact
- Default (background) mode is broken for any navigation command on this cloak/Chromium/macOS combination.
webcmd-adapter-eval (actor + peer) cannot run: background kills every step, and even the foreground workaround can only run one profile at a time on free tier.
- The error message (
Target page, context or browser has been closed) gives no indication of the real cause, costing a lot of debugging time.
Suggested fixes
- Background launch reliability (macOS): prevent the
open -g -n instance from being sudden-terminated — e.g. launch the cloak binary directly (like the foreground path) instead of via LaunchServices, or add flags that opt the process out of App Nap / sudden termination. Alternatively, detect the immediate disconnect and fail with a clear message instead of a later page.goto crash.
- Clear error mapping: map browser exit code 76 / an immediate post-launch disconnect to an actionable error, e.g.:
CloakBrowser session could not start. On the free tier only one browser can run at a time — close other profiles or set a Pro CLOAKBROWSER_LICENSE_KEY.
instead of the generic Target page, context or browser has been closed.
- Docs: note that concurrent profiles require a CloakBrowser tier with ≥2 sessions, and that background mode is currently unreliable on macOS (use
WEBCMD_WINDOW=foreground).
Workarounds (current)
export WEBCMD_WINDOW=foreground for single-profile runs.
- Run profiles strictly one at a time; release cleanly with
webcmd daemon stop (not pkill, which leaves the free-tier session slot stuck) before switching profiles.
- For true concurrency, a paid CloakBrowser license (≥2 sessions) is required.
Background-mode browser launch fails, and concurrent profiles surface a cryptic error (CloakBrowser free-tier session cap)
Summary
Two related problems make multi-profile / adapter-eval runs unusable, both surfacing as the same cryptic error:
After tracing it end to end, the webcmd daemon and profile multiplexing are correct — the failures originate in the CloakBrowser launch layer:
page.gotofails withTarget page, context or browser has been closed.The net effect: the twitter adapter eval (
webcmd-adapter-eval, actor/peer profiles) fails on every step, and the error message points nowhere useful.Environment
v0.5.20.4.5chromium-150.0.7871.114.3-proCLOAKBROWSER_LICENSE_KEY/license.key)Reproduction
Case 1 — background mode, single profile
Result:
Case 2 — two profiles concurrently (foreground)
The second launch exits 76 and
page.gotofails.Evidence (daemon instrumentation)
With logging added at the launch and context-
closepoints, plusDEBUG=pw:browser:Background, single profile — browser disconnects on its own ~320ms after connect:
context 'close'andbg browser DISCONNECTEDfire at the same timestamp — nothing in webcmd closed it; the Chromium process exited by itself.psshows zero cloakbrowser processes before the run and none lingering after.Foreground, second concurrent profile — exit code 76:
Same profile dir works fine when launched alone in foreground; it only dies when a second browser is already live → consistent with CloakBrowser free-tier "1 concurrent session."
Root cause
launchDarwinBackgroundPersistentContext,src/browser/runtime/local-cloak/darwin-background-launch.ts) starts Chromium via/usr/bin/open -g -n …and attaches over CDP. The-g(hidden, no-window) LaunchServices instance appears to be sudden-terminated by macOS shortly after launch. The foreground path (chromium.launchPersistentContext, Playwright-managed) keeps a single browser alive, which is whyWEBCMD_WINDOW=foreground"works" for one profile.Impact
webcmd-adapter-eval(actor + peer) cannot run: background kills every step, and even the foreground workaround can only run one profile at a time on free tier.Target page, context or browser has been closed) gives no indication of the real cause, costing a lot of debugging time.Suggested fixes
open -g -ninstance from being sudden-terminated — e.g. launch the cloak binary directly (like the foreground path) instead of via LaunchServices, or add flags that opt the process out of App Nap / sudden termination. Alternatively, detect the immediate disconnect and fail with a clear message instead of a laterpage.gotocrash.WEBCMD_WINDOW=foreground).Workarounds (current)
export WEBCMD_WINDOW=foregroundfor single-profile runs.webcmd daemon stop(notpkill, which leaves the free-tier session slot stuck) before switching profiles.