Skip to content

Multi-browser setups (Dia/Arc + Chrome installed): stale Chrome DevToolsActivePort shadows the active browser; recovery flow force-opens Google Chrome #425

Description

@bubischmampf

Environment

  • macOS 15 (Darwin 25.4), browser-harness 0.1.0 (git, current main @ 6d20866)
  • Primary browser: Dia (Chromium-based), remote debugging enabled via the chrome://inspect/#remote-debugging checkbox, listening on 127.0.0.1:9222. Note: with the new consent model, /json/version on that port returns 404, and a per-connection "Allow remote debugging" dialog is shown in the browser.
  • Google Chrome is installed but was not running. A stale DevToolsActivePort file (pointing at a dead ephemeral port) was left behind in ~/Library/Application Support/Google/Chrome from an earlier Chrome session that had the inspect checkbox ticked.

TL;DR

On a machine where the user's daily browser is a non-Chrome Chromium (Dia, Arc, Edge, ...) but Chrome is also installed, the harness (1) lets a stale Chrome DevToolsActivePort shadow the healthy target browser during discovery, and (2) on failure force-opens Google Chrome specifically. Combined effect in our case: the agent ended up silently automating a freshly-launched Chrome (without the user's logins) instead of the user's actual browser, and Chrome kept popping up on chrome://inspect/#remote-debugging during the task.

What happened (real-world sequence)

  1. Agent runs a task. Dia is healthy on 9222 with a valid DevToolsActivePort in its user-data dir.
  2. get_ws_url() (daemon.py) walks PROFILES in order. Chrome's dir ranks above Dia's, so the stale Chrome file is matched first. The code then polls the dead port for 30s and raises ("DevTools is not live yet") — it never advances to Dia's entry later in PROFILES.
  3. ensure_daemon() matches the error via _needs_chrome_remote_debugging_prompt() and calls _open_chrome_inspect(), which on macOS runs tell application "Google Chrome" ... — hardcoded. Wrong browser for Dia/Arc/Edge users; the user watches Chrome open on the inspect page repeatedly (once per cold harness invocation).
  4. Because Chrome's inspect checkbox happened to still be ticked, the freshly launched Chrome started a debug server and wrote a new, live DevToolsActivePort. From that moment Chrome wins every discovery, and the retry connects to Chrome. The task "succeeded" — in the wrong browser, without the user's logins.

Bug 1: discovery stops at the first DevToolsActivePort, even if its port is dead

In get_ws_url(), the PROFILES loop raises after the 30s poll on the first file found instead of moving on to the next profile. A leftover file from any higher-ranked browser permanently shadows a healthy lower-ranked one. (Chromium does not clean up DevToolsActivePort on browser quit, so stale files are the norm, not the exception.)

Suggested fix: quick-probe each candidate (is anything listening on that port?) and skip dead ones, preferring a live endpoint over list order; only fall into the 30s wait/raise when no candidate is live.

Bug 2: _open_chrome_inspect() hardcodes Google Chrome on macOS

For users whose browser is Dia/Arc/Edge, the consent checkbox lives in their browser, so opening Google Chrome is both ineffective and harmful (see step 4 above: it can mint a fresh live debug endpoint in the wrong browser). Related but distinct from #290 (Windows: webbrowser.open() can't handle chrome://).

Suggested fix: open the inspect page in the browser owning the profile dir that discovery matched (or at minimum the system default browser), instead of hardcoded Chrome.

Bug 3 (minor): _is_local_chrome_mode() ignores BU_CDP_URL

It only checks BU_CDP_WS. A user who explicitly pins an endpoint via BU_CDP_URL still gets the chrome://inspect popup flow when the connection fails (e.g., while the per-connection "Allow remote debugging" consent dialog is pending in the target browser and the WS handshake times out).

Suggested fix: treat an explicit BU_CDP_URL like BU_CDP_WS — a user pinning an endpoint doesn't want the Chrome UI recovery flow.

Workaround we use now

A pre-flight script reads the target browser's DevToolsActivePort and writes BU_CDP_WS=ws://127.0.0.1:9222<path> into the repo .env. That bypasses discovery entirely and (because BU_CDP_WS is set) disables the Chrome recovery flow. Works reliably, including across browser restarts (script refreshes the UUID and restarts the daemon when it changes).

Happy to send a PR for any/all of the three fixes if you're open to it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions