Repository navigation
[Regression]: middle / modifier click intermittently fails to open a new tab on Playwright 1.62.x #42142
Description
Activity
Hey! Thanks for reporting this.
The most likely root cause of this issue appears to be related to changes made in version 1.62.0 that affect the handling of new tab openings. While the specific code changes are not detailed in the issue, the problem is isolated to the functionality that manages new tab interactions. The affected code may reside in the
page.tsfile or related modules that handle browser interactions.A reasonable direction for fixing this issue would be to investigate the changes made in version 1.62.0 that relate to tab management and ensure that the logic for handling middle and modifier clicks is functioning as intended.
If no one is currently working on this, I'd be happy to take a look and put together a fix.
Thanks for the exceptionally clean MRE — the version table and the "no JavaScript, pure browser default action" framing made this easy to confirm.
Reproduced on 1.62.1, and it looks already fixed on tip-of-tree.
What I ran:
- 1.62.1 — your MRE unchanged,
--repeat-each=25 --workers=16on a 4-core box (heavy oversubscription): 2/50 failed withwaitForURL: Test timeout of 30000ms exceeded. Matches your report. - tip-of-tree (1.63.0-next) — the same scenario condensed to a self-contained spec (middle-click and ControlOrMeta click, plain
<a href>,context.waitForEvent('page')+waitForURL): 0 failures across 50 tests @ 16 workers and 100 tests @ 32 workers (8× oversubscription). Could not get it to fail.
Both runs use the same default headless-shell binary, so it's an apples-to-apples comparison.
The relevant difference is the bundled browser: 1.62.x ships Chromium
chromium-1234, tip-of-tree shipschromium-1237. This is a browser-default-action bug (opening a background tab with nothing in the page to interfere), and it disappears with the newer Chromium roll — consistent with an upstream fix that came in after 1.62.x was cut.So: nothing to change in the Playwright test code — the intermittent "new tab never opens / never navigates" behavior is gone on the current Chromium. It should ride out with the next release that carries
chromium-1237. If you can, giving@playwright/test@nexta spin against your real app would be a useful confirmation from your side.Triaged by the Playwright bot - agent run
- 1.62.1 — your MRE unchanged,
I've just tested it with
1.63.0-alpha-2026-08-06and it still fails:$ npm i -D @playwright/test@next changed 3 packages, and audited 4 packages in 35s found 0 vulnerabilities $ npx playwright install Downloading Chrome for Testing 152.0.7977.8 (playwright chromium v1237) from https://cdn.playwright.dev/builds/cft/152.0.7977.8/linux64/chrome-linux64.zip 184.7 MiB [====================] 100% 0.0s Chrome for Testing 152.0.7977.8 (playwright chromium v1237) downloaded to ... ... $ npx playwright --version Version 1.63.0-alpha-2026-08-06 $ npx playwright test --repeat-each=25 --workers=16 ... 2 failed [chromium] › tests/new-tab.spec.ts:3:5 › middle click opens a new tab ────────────────────────── [chromium] › tests/new-tab.spec.ts:3:5 › middle click opens a new tab ────────────────────────── 48 passed (33.5s)npx envinfo --preset playwright
System: OS: Linux 7.0 Ubuntu 24.04.4 LTS 24.04.4 LTS (Noble Numbat) CPU: (14) x64 Intel(R) Core(TM) Ultra 5 125U Memory: 29.22 GB / 46.52 GB Container: Yes Binaries: Node: 22.23.0 - /run/user/1000/fnm_multishells/308728_1786008511663/bin/node npm: 10.9.8 - /run/user/1000/fnm_multishells/308728_1786008511663/bin/npm bun: 1.3.8 - /home/yurii/.bun/bin/bun IDEs: VSCode: 1.124.2 - /usr/bin/code Languages: Bash: 5.2.21 - /usr/bin/bash npmPackages: @playwright/test: ^1.63.0-alpha-2026-08-06 => 1.63.0-alpha-2026-08-06Hi, I'm the Playwright bot and I took another look — thanks for coming back with the
@nextnumbers.This is a live regression, still present on tip-of-tree. I can confirm it, and I'm correcting the earlier triage on this thread: it is not fixed by the newer Chromium roll. Clean on 1.61.1, broken from 1.62.0 onward, and still broken on
1.63.0-alphawithchromium-1237.What I ran (your MRE, unchanged, on a 4-core box — heavy oversubscription at 16 workers)
@playwright/test Chromium Result 1.61.1 headless-shell v1228 0 / 300 failed (3× --repeat-each=50)1.62.1 headless-shell v1234 2 / 50 failed ( --repeat-each=25)1.63.0-alpha ( @next)headless-shell v1237 8 / 300 failed (3× --repeat-each=50)Failure is the one you reported —
browserContext.waitForEvent('page')/waitForURLhangs until the 30s deadline; the background tab either never opens or never navigates. It's timing-dependent, so a single 50-test run often passes clean — it takes repetition under load to surface, which is why the earlier "0 failures on ToT" run was misleading.Command:
PLAYWRIGHT_HTML_OPEN=never npx playwright test --repeat-each=50 --workers=16Condensed self-contained repro
Same trigger as your MRE, boiled down to our fixtures (still needs load/parallelism to surface — one run passes):
test('middle click opens a background tab', { annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright/issues/42142' } }, async ({ page, context, server }) => { server.setRoute('/', (req, res) => { res.writeHead(200, { 'content-type': 'text/html' }); res.end('<a href="/target.html">Open target</a>'); }); server.setRoute('/target.html', (req, res) => { res.writeHead(200, { 'content-type': 'text/html' }); res.end('<h1>Target</h1>'); }); await page.goto(server.PREFIX + '/'); const popupPromise = context.waitForEvent('page'); await page.getByRole('link', { name: 'Open target' }).click({ button: 'middle' }); await (await popupPromise).waitForURL('**/target.html'); });
Since 1.61.1 never fails across the full range you tried and the break lands squarely on 1.62.0, this looks like a real regression on our side that the Chromium update didn't touch. I'm a first pass, so I've left the root cause for a maintainer rather than guessing — but the boundary is clear and the repro is solid.
Triaged by the Playwright bot.
Triaged by the Playwright bot - agent run
Reacted by Yurii MotovHi, I’d like to investigate this regression.
My plan is to reproduce it using the provided repository, compare the behavior
between 1.61.1 and 1.62.x, and identify whether the failure is related to input
dispatch, modifier handling, or new-page event synchronization.If I can isolate the regression, I’ll add a focused regression test and propose
a minimal fix.Please let me know if someone is already working on this.
Thanks.
My agent bisected this to https://chromium-review.googlesource.com/c/chromium/src/+/7987972, i've filed this against Chromium: https://issues.chromium.org/issues/543471700
Reacted by Yurii MotovA possible optional aid for this regression environment comparison: ReproProof v0.4.0 can emit a redacted, verifiable receipt for a single Playwright run, so the 1.61.1→1.62.x regression conditions can be compared without sharing private paths. A normal minimal reproduction remains required; the receipt is supplemental only. If someone is willing to run one independent trial, please execute
reproproof verify --no-replayfirst and share only the verification result—never raw JSON, secrets, or private paths. No adoption commitment requested; feedback/tracking is at shleder/reproproof#18.- assigned and unassigned
on Aug 24, 2026 We have had this problem intermittently for a long time, before 1.60, using a control-click to open a new tab. Random failures to navigate occurred a few times a week.
The change we made was to not use the headless shell. In playwright.config.ts we added this to all the projects:
channel: 'chromium', // full chromium, not the headless shellSince then, we have not had a new tab failure for over a month.
We see what looks like another symptom of this regression: on Linux, the renderer of the background tab that a modifier click opens crashes with SIGSEGV when the browser context is closed.
Environment
playwright-core/@playwright/test1.63.0,chromium-headless-shellv1243 (Chromium 153.0.8010.12)- Linux arm64 (Debian bookworm container, Node 24) and Linux x86_64 (CI, Docker runner)
- core dumps enabled (
ulimit -c unlimited)
What we see
- An e2e suite (1 worker, all tests green, no retries) leaves three core dumps per run on both architectures. They come from the three tests that click an
<a href>withmodifiers: ['ControlOrMeta']and then end: when those clicks no longer open a tab, the dumps are gone. - Each core is a
rendererprocess:SIGSEGV,si_code1 (SEGV_MAPERR), fault address0x568, i.e. a field read through a NULL pointer. Identical on arm64 and x86_64. - The crashed renderer's memory holds no URL of the page under test, only
about:blank: the background tab never navigated, which matches the "tab never opens / never navigates" failure in this issue. - The core file is already there right after
context.close(), beforebrowser.close().
Minimal repro (no test runner, a single link):
// Run from an empty directory with `ulimit -c unlimited`: with the default // relative core_pattern the renderer's core file lands in that directory. const http = require('node:http'); const { chromium } = require('playwright-core'); (async () => { const server = http.createServer((req, res) => { res.writeHead(200, { 'content-type': 'text/html' }); res.end('<a id="tile" href="#/next">tile</a>'); }); await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve)); const base = `http://127.0.0.1:${server.address().port}`; const browser = await chromium.launch(); const context = await browser.newContext(); const page = await context.newPage(); await page.goto(`${base}/`); await page.locator('#tile').click({ modifiers: ['ControlOrMeta'] }); await page.waitForTimeout(250); await context.close(); // the background tab's renderer crashes here await new Promise((resolve) => setTimeout(resolve, 2000)); await browser.close(); server.close(); })();
Results of this snippet on linux/arm64, 3 runs each (for the
channel: 'chromium'row only thelaunch()call changes):Build Renderer core dumps 1.63.0, headless shell v1243 (Chromium 153.0.8010.12) 3/3 1.63.0, channel: 'chromium'(Chromium 153.0.8010.12)0/3 1.61.1, headless shell v1228 (Chromium 149.0.7827.0) 0/3 So only the headless shell crashes, and 1.61.1 does not: the same boundary as this issue.
In our runs nothing crashed without the modifier click (no click, a plain click, or a second page from
context.newPage()). Closing the new tab before the context is not a reliable workaround: depending on the page and the timing it avoided the crash in some runs and not in others.What we use instead: the test sends the real modifier click with a window-level bubble listener in place, which records
event.defaultPreventedafter the page's own handlers and then callspreventDefault(), so no tab opens; the test asserts that the page left the click to the browser.Some data that may help narrow down the stuck step. In our case the tab does open and commit; Playwright just never finishes setting it up.
Setup: Playwright 1.63.0, default headless shell (chromium-1243, Chromium 153.0.8010.12), Ubuntu x86_64, 16 cores. Ctrl+click (
click({ modifiers: ['Control'] })) on a plain<a href>in a Next.js production build. Tests run one at a time, with no extra load.Rate: 5 of 60 clicks (about 8%) in a loop that repeats the same click. An earlier run was 3 of 60.
In every miss:
- The browser's own target list (
Target.getTargetson abrowser.newBrowserCDPSession()) shows exactly one newtype: "page"target in the context:attached: true;- the expected URL;
- the app's document title, which Chromium shows only after the navigation commits. Before that it reports the pending URL.
context.pages().lengthstays at 1, and nopageevent arrives, even after 45 s.- The tab's video recording has already started and shows the rendered page.
Closing it reveals the wait. When we close the stranded tab with
Target.closeTarget, Playwright emits the contextpageevent for it 6–7 ms later (already closed), immediately followed byclose. This happened 5 of 5 times. That looks like the page's initialization was blocked on an await with no timeout until the session was disposed. Could it be the same kind of unbounded wait on a renderer reply that #42883 and #42930 handle forconnectOverCDP?How this differs from the about:blank crash reported above: there the tab never navigated. Here the tab commits; only Playwright's initialization of it hangs.
Workaround we use, until there is a fix:
- Snapshot the page targets before the click.
- Poll
Target.getTargetsfor exactly one new page target with the expected path and title. - Close it with
Target.closeTarget.
We don't use
setAutoAttachorsetDiscoverTargets. It passed 60/60 on the same clicks where thepageevent missed 5.- The browser's own target list (
Another data point from before the 1.62.0 boundary: the same miss happens on 1.60.0 with the default headless shell, chrome-headless-shell 148.0.7778.96 (revision 1223), which predates the Chromium CL bisected above. The
pw:protocollogs show where page initialization stops.Setup: Linux x86_64 (Ubuntu 24.04), 2 workers, no retries. The whole run (runner, browser and the local static server) was pinned to 2 cores with
taskset -c 0,1, with a host load average of 4–10. The test Ctrl+clicks a plain same-origin<a href="/page/#fragment">withclick({ modifiers: ['Control'] })and waits oncontext.waitForEvent('page').Rates:
- 19 of 600 runs of the real test, across three builds of the same page.
- Probes that wait 8 s for the
pageevent:- 3/100 from the full page;
- 4/100 from a bare opener made with
page.setContent('<a id="go" href="…">…</a>'); - 1/100 when that bare link opens a
text/plainfile, so no page script runs in either tab.
Where it stops: I logged 180 new tabs with
DEBUG=pw:protocol.Page.getFrameTreereported the main frame URL asabout:blankfor 127 tabs, as the already committed URL for 31, and as":"for 22.- All 7 failures are the 7
":"tabs that never receivedPage.frameNavigated. - The other 15
":"tabs passed becausePage.frameNavigatedarrived in the same millisecond as theRuntime.runIfWaitingForDebuggerresponse, 70–132 ms after attach. - In the failing tabs the new document still commits:
Runtime.executionContextsCleared/Createdfor the page's origin arrive 6–60 ms later, the subresources load, and the new loader gets itsDOMContentLoadedandloadlifecycle events. ButPage.frameNavigatedfor that frame never arrives on any session, and the target stays attached until the context closes.
When
Page.getFrameTreereports":",FrameSession._initializetreats the frame as the initial empty page and adds_firstNonInitialNavigationCommittedPromiseto the promises it awaits. Only a non-initialPage.frameNavigatedresolves that promise, so the page is never reported.That answers Colton Jones (@CoJoA13)'s question above: this promise is the unbounded wait. Disposing the session rejects it, which fits the
pageevent arriving just beforeclosewhen the target is closed.Failing tab, from its session (URLs replaced; network body fetches and Playwright's own evaluate calls left out):
+ 0ms EVENT Target.attachedToTarget {"type":"page","url":"","waitingForDebugger":true} + 8ms SEND Page.enable / Page.getFrameTree / Log.enable / Page.setLifecycleEventsEnabled / Runtime.enable / Page.addScriptToEvaluateOnNewDocument / Network.enable / Target.setAutoAttach / … / Runtime.runIfWaitingForDebugger + 11ms EVENT Page.frameStartedNavigating {"url":"http://127.0.0.1:PORT/page/#fragment","loaderId":"F57C9F7A","navigationType":"differentDocument"} + 13ms EVENT Network.requestWillBeSent {"loaderId":"F57C9F7A","type":"Document"} + 36ms EVENT Network.responseReceived {"loaderId":"F57C9F7A","type":"Document","status":200} + 71ms RESP Page.enable + 71ms RESP Page.getFrameTree {"frame":{"loaderId":"9DE2AECD","url":":","securityOrigin":"://"}} + 72ms SEND Page.createIsolatedWorld + 72ms EVENT Page.lifecycleEvent {"loaderId":"9DE2AECD","name":"commit"} (+ DOMContentLoaded, networkAlmostIdle, networkIdle for 9DE2AECD) + 77ms RESP Page.setLifecycleEventsEnabled / Runtime.enable / … / Runtime.runIfWaitingForDebugger (every init command answered) + 77ms EVENT Page.lifecycleEvent {"loaderId":"F57C9F7A","name":"init"} + 87ms EVENT Page.frameStartedLoading + 107ms EVENT Runtime.executionContextsCleared + 107ms EVENT Runtime.executionContextCreated {"origin":"http://127.0.0.1:PORT","isDefault":false} + 107ms EVENT Runtime.executionContextCreated {"origin":"http://127.0.0.1:PORT","isDefault":true} + 446ms EVENT Page.lifecycleEvent {"loaderId":"F57C9F7A","name":"DOMContentLoaded"} + 468ms EVENT Page.lifecycleEvent {"loaderId":"F57C9F7A","name":"load"} + 468ms EVENT Page.frameStoppedLoading + 2038ms EVENT Page.lifecycleEvent {"loaderId":"F57C9F7A","name":"networkIdle"} +28295ms EVENT Target.detachedFromTarget (context closed by the test timeout; no Page.frameNavigated for this frame anywhere in the log)On 1.62 and later, Chromium reports
""instead of":"for the initial empty document, and #41464 accepts both. So the misses reported here on 1.62 and 1.63 can reach the same wait. I have not verified that they do.The missing
Page.frameNavigatedlooks like a Chromium bug. On Playwright's side, a fallback would unblock initialization when the main frame reports lifecycle events for a loader other than the onePage.getFrameTreereturned, for example by reading the frame tree again.We work around it the way IF (@illusionfield) describes: a window bubble-phase listener records
event.defaultPreventedafter the page's own handlers and then cancels the default, so no tab opens.
Last Good Version
1.61.1
First Bad Version
1.62.0
Steps to reproduce
git clone https://github.com/YuriiMotov/playwright-1.62-new-tab-mre.gitcd playwright-1.62-new-tab-mrenpm installnpx playwright --version- expectedVersion 1.62.1npx playwright test --repeat-each=25 --workers=16- see several tests fail withTest timeout of 30000ms exceedednpm pkg set devDependencies.@playwright/test=1.61.1 && npm installnpx playwright --version- expectedVersion 1.61.1npx playwright test --repeat-each=25 --workers=16- see tests passExpected behavior
I expect tests pass on 1.62.x as it was on 1.61.1 and previous versions.
Actual behavior
Several tests fail with
Test timeout of 30000ms exceededAdditional context
Only tests that attempt to open page in a new tab are affected.
--workers=16here is to imitate overloaded machine. In fact in our case it fails with--workers=1in CI.See report generated by Claude Code: https://github.com/YuriiMotov/playwright-1.62-new-tab-mre/blob/master/README.md
Environment
System: OS: Linux 7.0 Ubuntu 24.04.4 LTS 24.04.4 LTS (Noble Numbat) CPU: (14) x64 Intel(R) Core(TM) Ultra 5 125U Memory: 28.49 GB / 46.52 GB Container: Yes Binaries: Node: 22.23.0 - /run/user/1000/fnm_multishells/1402339_1785955498713/bin/node npm: 10.9.8 - /run/user/1000/fnm_multishells/1402339_1785955498713/bin/npm bun: 1.3.8 - /home/yurii/.bun/bin/bun IDEs: VSCode: 1.124.2 - /usr/bin/code Languages: Bash: 5.2.21 - /usr/bin/bash npmPackages: @playwright/test: 1.62.1 => 1.62.1