You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Regression]: middle / modifier click intermittently fails to open a new tab on Playwright 1.62.x #42142
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.ts file 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=16 on a 4-core box (heavy oversubscription): 2/50 failed with waitForURL: 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 ships chromium-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@next a spin against your real app would be a useful confirmation from your side.
Hi, I'm the Playwright bot and I took another look — thanks for coming back with the @next numbers.
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-alpha with chromium-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') / waitForURL hangs 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=16
Condensed 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>');});awaitpage.goto(server.PREFIX+'/');constpopupPromise=context.waitForEvent('page');awaitpage.getByRole('link',{name: 'Open target'}).click({button: 'middle'});await(awaitpopupPromise).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.
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.
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 shell
Since 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.
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> with modifiers: ['ControlOrMeta'] and then end: when those clicks no longer open a tab, the dumps are gone.
Each core is a renderer process: SIGSEGV, si_code 1 (SEGV_MAPERR), fault address 0x568, 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(), before browser.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.consthttp=require('node:http');const{ chromium }=require('playwright-core');(async()=>{constserver=http.createServer((req,res)=>{res.writeHead(200,{'content-type': 'text/html'});res.end('<a id="tile" href="#/next">tile</a>');});awaitnewPromise((resolve)=>server.listen(0,'127.0.0.1',resolve));constbase=`http://127.0.0.1:${server.address().port}`;constbrowser=awaitchromium.launch();constcontext=awaitbrowser.newContext();constpage=awaitcontext.newPage();awaitpage.goto(`${base}/`);awaitpage.locator('#tile').click({modifiers: ['ControlOrMeta']});awaitpage.waitForTimeout(250);awaitcontext.close();// the background tab's renderer crashes hereawaitnewPromise((resolve)=>setTimeout(resolve,2000));awaitbrowser.close();server.close();})();
Results of this snippet on linux/arm64, 3 runs each (for the channel: 'chromium' row only the launch() call changes):
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.defaultPrevented after the page's own handlers and then calls preventDefault(), 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.getTargets on a browser.newBrowserCDPSession()) shows exactly one new type: "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().length stays at 1, and no page event 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 context page event for it 6–7 ms later (already closed), immediately followed by close. 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 for connectOverCDP?
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.getTargets for exactly one new page target with the expected path and title.
Close it with Target.closeTarget.
We don't use setAutoAttach or setDiscoverTargets. It passed 60/60 on the same clicks where the page event missed 5.
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:protocol logs 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"> with click({ modifiers: ['Control'] }) and waits on context.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 page event:
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/plain file, so no page script runs in either tab.
Where it stops: I logged 180 new tabs with DEBUG=pw:protocol. Page.getFrameTree reported the main frame URL as about:blank for 127 tabs, as the already committed URL for 31, and as ":" for 22.
All 7 failures are the 7 ":" tabs that never received Page.frameNavigated.
The other 15 ":" tabs passed because Page.frameNavigated arrived in the same millisecond as the Runtime.runIfWaitingForDebugger response, 70–132 ms after attach.
In the failing tabs the new document still commits: Runtime.executionContextsCleared/Created for the page's origin arrive 6–60 ms later, the subresources load, and the new loader gets its DOMContentLoaded and load lifecycle events. But Page.frameNavigated for that frame never arrives on any session, and the target stays attached until the context closes.
When Page.getFrameTree reports ":", FrameSession._initialize treats the frame as the initial empty page and adds _firstNonInitialNavigationCommittedPromise to the promises it awaits. Only a non-initial Page.frameNavigated resolves 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 page event arriving just before close when the target is closed.
Failing tab, from its session (URLs replaced; network body fetches and Playwright's own evaluate calls left out):
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.frameNavigated looks 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 one Page.getFrameTree returned, for example by reading the frame tree again.
We work around it the way IF (@illusionfield) describes: a window bubble-phase listener records event.defaultPrevented after the page's own handlers and then cancels the default, so no tab opens.
Activity
Mahnoor-Zaffar commentedon Aug 6, 2026
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.
github-actions commentedon Aug 6, 2026
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:
--repeat-each=25 --workers=16on a 4-core box (heavy oversubscription): 2/50 failed withwaitForURL: Test timeout of 30000ms exceeded. Matches your report.<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
YuriiMotov commentedon Aug 6, 2026
I've just tested it with
1.63.0-alpha-2026-08-06and it still fails:npx envinfo --preset playwright
github-actions commentedon Aug 6, 2026
Hi, 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)
--repeat-each=50)--repeat-each=25)@next)--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):
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
alirezaedalat commentedon Aug 6, 2026
Hi, 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.
Skn0tt commentedon Aug 7, 2026
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
daddyman commentedon Sep 1, 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.
illusionfield commentedon Sep 22, 2026
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)ulimit -c unlimited)What we see
<a href>withmodifiers: ['ControlOrMeta']and then end: when those clicks no longer open a tab, the dumps are gone.rendererprocess:SIGSEGV,si_code1 (SEGV_MAPERR), fault address0x568, i.e. a field read through a NULL pointer. Identical on arm64 and x86_64.about:blank: the background tab never navigated, which matches the "tab never opens / never navigates" failure in this issue.context.close(), beforebrowser.close().Minimal repro (no test runner, a single link):
Results of this snippet on linux/arm64, 3 runs each (for the
channel: 'chromium'row only thelaunch()call changes):channel: 'chromium'(Chromium 153.0.8010.12)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.CoJoA13 commentedon Sep 26, 2026
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:
Target.getTargetson abrowser.newBrowserCDPSession()) shows exactly one newtype: "page"target in the context:attached: true;context.pages().lengthstays at 1, and nopageevent arrives, even after 45 s.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:
Target.getTargetsfor exactly one new page target with the expected path and title.Target.closeTarget.We don't use
setAutoAttachorsetDiscoverTargets. It passed 60/60 on the same clicks where thepageevent missed 5.gcharang commentedon Sep 30, 2026
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:
pageevent:page.setContent('<a id="go" href="…">…</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.":"tabs that never receivedPage.frameNavigated.":"tabs passed becausePage.frameNavigatedarrived in the same millisecond as theRuntime.runIfWaitingForDebuggerresponse, 70–132 ms after attach.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):
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.