Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

[Bug]: connectOverCDP kills the process with an uncaught assertion when an attached target has no browserContextId

Open
#43,638 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

@lazerg is already working on this.

Since Oct 26, 2026.

Assessment

Difficulty
3/5
Estimated time
1-2 days
Newbie friendliness
68/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
node.js, typescript

Research direction

Start in packages/playwright-core/src/server/chromium/crBrowser.ts at _onAttachedToTarget and read how it handles unsupported target types and sessions paused by waitForDebugger. Reproduce with the supplied mock CDP endpoint and connect.mjs, then inspect nearby Chromium browser tests for coverage. Done means a target without browserContextId no longer crashes connectOverCDP and the paused target is detached.

Written by the indexing model from the issue text.

Description

Version

1.64.1

Steps to reproduce

Playwright crashes when a browser reports a target without a profile id, a field the protocol says is optional. The crash is uncatchable, so the whole process dies, and it leaves the target frozen so every retry fails too.

package.json

{
    "name": "connect-over-cdp-repro",
    "private": true,
    "type": "module",
    "dependencies": {
        "playwright-core": "1.64.1",
        "ws": "^8.22.0"
    }
}

mock-cdp.mjs

// A minimal fake of a Chromium remote-debugging endpoint.
// It answers every request with an empty result, except the few connectOverCDP needs,
// and reports one shared worker target that has no browserContextId.
import http from "node:http";
import { WebSocketServer } from "ws";

const PORT = 9777;
const sharedWorker = {
    attached: true,
    canAccessOpener: false,
    targetId: "SHARED_WORKER_1",
    title: "",
    type: "shared_worker",
    url: "blob:http://localhost:1420/2c5b7d6e-5f82-4b1e-b9e1-563036a8446e"
};

const server = http.createServer((request, response) => {
    response.setHeader("content-type", "application/json");
    response.end(JSON.stringify({
        Browser: "Mock/1.0",
        "Protocol-Version": "1.3",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Mock",
        webSocketDebuggerUrl: `ws://127.0.0.1:${ PORT }/devtools/browser/mock`
    }));
});

const sockets = new WebSocketServer({ server });
sockets.on("connection", (socket) => {
    const send = (message) => socket.send(JSON.stringify(message));
    socket.on("message", (data) => {
        const { id, method, sessionId } = JSON.parse(String(data));
        const reply = (result) => send({ id, result, sessionId });
        switch (method) {
            case "Browser.getVersion":
                reply({ jsVersion: "0", product: "Mock/1.0", protocolVersion: "1.3", revision: "0", userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Mock" });
                break;
            case "Target.getBrowserContexts":
                reply({ browserContextIds: [] });
                break;
            case "Target.setAutoAttach":
                reply({});
                send({ method: "Target.attachedToTarget", params: { sessionId: "SESSION_SW_1", targetInfo: sharedWorker, waitingForDebugger: true } });
                break;
            case "Target.setDiscoverTargets":
                reply({});
                send({ method: "Target.targetCreated", params: { targetInfo: sharedWorker } });
                break;
            case "Target.attachToTarget":
                reply({ sessionId: "SESSION_SW_1" });
                send({ method: "Target.attachedToTarget", params: { sessionId: "SESSION_SW_1", targetInfo: sharedWorker, waitingForDebugger: true } });
                break;
            default:
                reply({});
        }
    });
});

server.listen(PORT, () => console.log(`mock endpoint on http://127.0.0.1:${ PORT }`));

connect.mjs

import { chromium } from "playwright-core";

try {
    const browser = await chromium.connectOverCDP("http://127.0.0.1:9777");
    console.log("connectOverCDP succeeded; contexts:", browser.contexts().length);
    await browser.close();
}
catch (error) {
    console.log("connectOverCDP failed:\n" + error.message.split("\n").slice(0, 12).join("\n"));
    process.exitCode = 1;
}

Run:

npm install
node mock-cdp.mjs &
node connect.mjs
Expected behavior

connectOverCDP resolves. A target the library cannot place in a context should be detached and ignored, which is what _onAttachedToTarget already does for targets of type other, and what shared workers end up as anyway: the method's final comment says they are intentionally left alone so that a worker waiting on Runtime.runIfWaitingForDebugger is not stalled.

Actual behavior

The process dies. The try/catch in connect.mjs never runs, because the assertion fires inside the event handler:

playwright-core/lib/coreBundle.js:885
    throw new Error(message || "Assertion error");
          ^

Error: targetInfo: {
  "attached": true,
  "canAccessOpener": false,
  "targetId": "SHARED_WORKER_1",
  "title": "",
  "type": "shared_worker",
  "url": "blob:http://localhost:1420/2c5b7d6e-5f82-4b1e-b9e1-563036a8446e"
}
    at assert (playwright-core/lib/coreBundle.js:885:11)
    at _CRBrowser._onAttachedToTarget (playwright-core/lib/coreBundle.js:39842:9)
    at _CRSession.emit (node:events:509:20)

Source: packages/playwright-core/src/server/chromium/crBrowser.ts, _onAttachedToTarget, the assert(targetInfo.browserContextId, ...) line that precedes the type dispatch. Two consequences follow from its position:

  1. Even target types that the method would otherwise ignore (shared_worker, worker) can crash the client, because the assertion runs before the type is examined.
  2. Auto-attach was requested with waitForDebugger: true. The assertion throws before the session is detached, so nothing ever resumes the target. In the real case below, the worker stayed paused and attached: true for the life of its document, and every later connectOverCDP failed on it again.
Additional context

Proposed fix

Treat a target without a browser context like an unsupported target: detach and return, before the assertion.

   _onAttachedToTarget({ targetInfo, sessionId, waitingForDebugger }) {
     if (targetInfo.type === 'browser')
       return;
     const session = this._session.createChildSession(sessionId);
-    assert(targetInfo.browserContextId, 'targetInfo: ' + JSON.stringify(targetInfo, null, 2));
+    if (!targetInfo.browserContextId) {
+      session.detach().catch(() => {});
+      return;
+    }
     let context = this._contexts.get(targetInfo.browserContextId) || null;

Detaching also releases a target paused by waitForDebugger, which removes the secondary effect. With this change applied to 1.64.1 as a package patch, connect.mjs prints connectOverCDP succeeded; contexts: 1 against the mock, and the WebView2 setup above connects reliably, including when the Vite ping worker appears mid-session.

If a stricter stance is preferred for page targets, the check could detach only non-page types and keep the assertion for page, but a page without a context has not been seen; the minimal change above seems sufficient.

Environment
System:
  OS: Windows 11 10.0.26300
  CPU: (32) x64 AMD Ryzen 9 7945HX with Radeon Graphics
  Memory: 3.61 GB / 31.21 GB
Binaries:
  Node: 26.3.1 - C:\Program Files\nodejs\node.EXE
  Yarn: 1.22.22 - C:\Users\hugoa\AppData\Local\pnpm\yarn.CMD
  npm: 9.6.7 - C:\Program Files\nodejs\npm.CMD
  pnpm: 12.15.0 - C:\Users\hugoa\AppData\Local\pnpm\bin\pnpm.CMD
Languages:
  Bash: 5.2.26 - C:\Program Files\Git\usr\bin\bash.EXE
npmPackages:
  playwright-core: 1.64.1 => 1.64.1
Dominant language
TypeScript
Stars
98.5k
Forks
6.7k
Avg merge
16h 5m
Merged PRs (30d)
286

Getting set up

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.

More from microsoft/playwright

All issues in microsoft/playwright

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.