Skip to content

[Bug]: Extension mode reconnect can leave the connect.html seed tab orphaned (two confirmed causes) #41864

Description

@dosxnjos

Splits out the confirmed, reproducible part of #41843 into a focused issue, as requested there. Two distinct, independently reproducible causes of the same symptom: after a reconnect through the extension (--extension), the freshly spawned connect.html seed tab is left behind — orphaned — while a separate new tab opens to serve the actual request.

Cause 1 — first tool call after reconnect is browser_tabs new

Repro (5/5):

  1. Connect via the extension, token-bypass flow.
  2. Force a reconnect (e.g. close the group's last tab, which tears the connection down per _checkLastTabDetached).
  3. Make the first tool call of the new connection browser_tabs {action: "new", url}.

Expected: the seed connect.html tab is reused or closed; only the requested tab remains.
Actual: Context.newTab() creates a second tab by design; the seed connect.html tab is left behind, alive and grouped.

09:37:03.784 pw:mcp:relay Extension connection established
09:37:03.837 pw:mcp:relay ← Playwright: Target.createTarget (id=19)

Root cause: Context.newTab() (packages/playwright-core/src/tools/backend/context.ts) has no awareness of the seed tab spawned by the token-bypass reconnect path, so it always creates a new tab rather than checking whether the current tab is just connection infrastructure.

Suggested fix: when Context.newTab() creates a tab, close any remaining page whose URL matches the extension's own connect.html?mcpRelayUrl= seed signature — that page is connection infrastructure, never a user target.

Cause 2 — the spawned connect page doesn't stay isolated from other tab groups

Repro (2/2, requires a second active Playwright connection/group already open):

  1. Have an existing Playwright extension connection/tab group active.
  2. Start a second, separate extension connection (new client) while the first is active.

Expected: the new connection's own connect.html seed tab attaches cleanly to its own connection, without interacting with any other connection's tab group.
Actual: the newly spawned tab doesn't stay out of tab-group territory it has no business being in. The exact mechanism isn't fully pinned down yet (likely Chrome inserting the new tab next to the active one and carrying over its group, but that's an inference, not confirmed) — what is confirmed, 2/2, is that when another Playwright connection's group happens to be sitting adjacent, the new tab ends up inside that neighboring group instead of staying ungrouped. That group's _onTabGroupChanged then attaches the new page, and the rightful connection's own attach fails — silently:

09:44:38.428 pw:mcp:relay Extension connection established
09:44:38.437 pw:mcp:error attach failed for tab 564270754
  (chrome-extension://.../connect.html?mcpRelayUrl=ws%3A%2F%2F...):
  Error: Another debugger is already attached to the tab with id: 564270754.
09:44:38.437 pw:mcp:error ANOMALY: setAutoAttach answered with 0 attached of 1 known tabs
09:44:38.439 pw:mcp:relay ← Playwright: Target.createTarget (id=5)

BrowserModel.enableAutoAttach() (packages/playwright-core/src/tools/mcp/browserModel.ts) swallows per-tab attach failures (.catch(logUnhandledError)) and reports Target.setAutoAttach successfully with an empty model, so Playwright sees zero pages and creates a fresh tab — ghosting the seed again.

A related swallowed-failure case, same shape, no second group needed — a load race where the seed tab is attached while still on its pre-navigation URL:

09:57:45.410 pw:mcp:error attach failed for tab 564270775 ():
  Error: Cannot access a chrome:// URL

(url was still empty/pending — chrome://new-tab-page under the hood — when chrome.debugger.attach arrived; isNonDebuggableUrl(undefined) is false, so nothing filtered it.)

Suggested fixes:

  1. The extension should never auto-attach its own connect page when it enters a group (url.startsWith(chrome.runtime.getURL('connect.html'))).
  2. enableAutoAttach() should not report silent success when 0 of N known tabs attached — retry once (covers the load race) and/or surface the failure.

Environment

  • Windows 11, branded Chrome (extension mode via --extension)
  • Both reproduced with DEBUG=pw:mcp:* logging on a local build whose relevant code paths are unmodified from upstream.

Happy to send PRs for either fix once triaged.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    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