Version
1.63.0
Steps to reproduce
Minimal reproduction: https://github.com/Tib-Gridello/playwright-dialog-race-repro
- Clone the repository.
- Run
npm install.
- Run
npx playwright install chromium.
- Run
npm run reproduce.
The reproduction starts Chromium with a CDP endpoint, attaches two independent Playwright processes to the same page, leaves the JavaScript dialog unclaimed in both clients, and triggers one alert.
Both Playwright processes receive the dialog and auto-dismiss it. One Page.handleJavaScriptDialog call wins; the other rejects because the dialog has already closed. In DialogManager.dialogDidOpen, the auto-dismiss path uses dialog._close().then(() => {}), so that rejection is unhandled and terminates the losing Playwright process.
This also reproduces on Playwright 1.60.0. The same auto-dismiss line is present on current main (07f1a6154795f055f341b8972086533e8e48b36f).
Expected behavior
The dialog is dismissed once and both Playwright clients remain connected. A failed best-effort auto-dismiss should not terminate the Playwright process when another CDP client already handled the dialog.
Actual behavior
One worker terminates deterministically on the first dialog:
ProtocolError: Protocol error (Page.handleJavaScriptDialog): No dialog is showing
at Dialog._dismiss (.../playwright-core/lib/coreBundle.js:13274:20)
at Dialog._close (.../playwright-core/lib/coreBundle.js:13287:22)
at DialogManager.dialogDidOpen (.../playwright-core/lib/coreBundle.js:13308:18)
Node.js v26.5.0
worker 2 exited: code=1 signal=null
Additional context
Issue #36627 reported the same protocol error around Electron beforeunload dialogs, but it was closed without a minimal reproduction. This report isolates a different, deterministic trigger: two independent CDP clients racing Playwright's implicit dialog dismissal.
The explicit cleanup path in removeDialogHandler already uses dialog._close().catch(() => {}); the implicit auto-dismiss path uses .then(() => {}) without a rejection handler. I can submit the corresponding one-line fix and a two-client regression test if this is approved for community contribution.
Environment
System:
OS: macOS 26.6.2
CPU: (18) arm64 Apple M5 Max
Memory: 2.34 GB / 48.00 GB
Binaries:
Node: 26.5.0 - /opt/homebrew/bin/node
npm: 11.17.0 - /opt/homebrew/bin/npm
npmPackages:
playwright: 1.63.0 => 1.63.0
Version
1.63.0
Steps to reproduce
Minimal reproduction: https://github.com/Tib-Gridello/playwright-dialog-race-repro
npm install.npx playwright install chromium.npm run reproduce.The reproduction starts Chromium with a CDP endpoint, attaches two independent Playwright processes to the same page, leaves the JavaScript dialog unclaimed in both clients, and triggers one alert.
Both Playwright processes receive the dialog and auto-dismiss it. One
Page.handleJavaScriptDialogcall wins; the other rejects because the dialog has already closed. InDialogManager.dialogDidOpen, the auto-dismiss path usesdialog._close().then(() => {}), so that rejection is unhandled and terminates the losing Playwright process.This also reproduces on Playwright 1.60.0. The same auto-dismiss line is present on current
main(07f1a6154795f055f341b8972086533e8e48b36f).Expected behavior
The dialog is dismissed once and both Playwright clients remain connected. A failed best-effort auto-dismiss should not terminate the Playwright process when another CDP client already handled the dialog.
Actual behavior
One worker terminates deterministically on the first dialog:
Additional context
Issue #36627 reported the same protocol error around Electron
beforeunloaddialogs, but it was closed without a minimal reproduction. This report isolates a different, deterministic trigger: two independent CDP clients racing Playwright's implicit dialog dismissal.The explicit cleanup path in
removeDialogHandleralready usesdialog._close().catch(() => {}); the implicit auto-dismiss path uses.then(() => {})without a rejection handler. I can submit the corresponding one-line fix and a two-client regression test if this is approved for community contribution.Environment
System: OS: macOS 26.6.2 CPU: (18) arm64 Apple M5 Max Memory: 2.34 GB / 48.00 GB Binaries: Node: 26.5.0 - /opt/homebrew/bin/node npm: 11.17.0 - /opt/homebrew/bin/npm npmPackages: playwright: 1.63.0 => 1.63.0