anomalyco / anomalyco/browser-control

CDP detaches after ~5-15s on heavy SPAs: banner auto-closes, 'Execution context destroyed' loop, session bound to dead target

Open
#67 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
407
Forks
20
Avg merge
9h 22m
Merged PRs (30d)
33

Description

Environment
  • browser-control CLI/relay: 0.5.1 (build 2026-08-23T23:42:36.863Z)
  • Extension: 0.0.24, protocol v2 (compatible)
  • Browser: Chrome/Edge 151.0.0.0, Linux x86_64 (X11)
  • browser-control doctor: all checks ok
Summary

Automating a heavy SPA (LinkedIn company-page admin editor) fails reproducibly: ~5–15s after navigation the CDP session drops — the Chromium "started debugging this browser" banner closes by itself, every page.evaluate then fails with Execution context was destroyed, most likely because of a navigation, and the relay declares the page unresponsive and recreates it. The session is then bound to the dead target, and subsequent executes fail with Debugger is not attached to the tab with id: <id> until the page is manually re-created. URL never changes during the loop, so it is the target site tearing down/reloading the renderer (presumably CDP detection) — but Browser Control's reaction to it (detach + recreate + stale binding) turns one bad page into a wedged session.

Repro
  1. browser-control execute 'await page.goto("https://www.linkedin.com/company/<id>/admin/edit/?editPageActiveTab=info", { waitUntil: "commit" })'
  2. Wait 5–15s (authenticated SPA, heavy).
  3. Any page.evaluate / snapshot now fails with Execution context was destroyed....
  4. Next execute reports The session default page was closed; created a new page + ...was unresponsive; created a new page; new page is about:blank.
  5. Re-goto → sometimes works once, then loops back to step 3.

Polling page.url() every 2.5s for 15s showed the same URL throughout while every evaluate context died — i.e. same-URL reload loop, not a real navigation.

Actual behavior
  • Debugger banner auto-closes a few seconds after attach (user-observed); CDP detaches mid-operation.
  • Relay recreates the page but the session keeps referencing the old target id → Protocol error (Page.navigate): Debugger is not attached to the tab with id: 97354.
  • Target selection flaps: status --json lists the user-attached target (activeTargets: 1), but an immediately-following execute --target-url linkedin returns "No existing attached page URL includes linkedin".
Expected behavior
  • On renderer teardown/reload: re-attach CDP to the same tab (the tab still exists) instead of recreating the page and orphaning the session binding.
  • Stale binding (Debugger is not attached to the tab with id) should self-heal: re-resolve the session's default target by URL/id before failing.
  • Target announce → select consistency: a target listed by status should be selectable by --target-url in the immediately following command.
Workarounds tried
  • Retry with longer settle (10–12s), waitUntil: commit/domcontentloaded, atomic goto+wait+act in one execute — works once occasionally, then degrades again.
  • User-attached tab via toolbar: attach flaps the same way (listed in status, unselectable seconds later).
  • Fresh session + fresh relay-created page: same loop on this site. Regular/light pages work fine.
Notes
  • Happy to capture BROWSER_CONTROL_DEBUG=1 traces or a recording on request (will omit all page content).
  • Repro URL is a LinkedIn admin page (auth-gated); happy to test against any provided heavy-SPA test page instead.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the CDP detach and target lifecycle paths used by execute, status --json, and --target-url, then reproduce the same-URL renderer teardown on a heavy SPA. Done means the existing tab is reattached without orphaning the session, stale target bindings recover, and a target reported by status remains selectable immediately afterward.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
cli, devtools, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.