← Back to microsoft/playwright
microsoft / playwright · Issue No. 42817
1.64.0-next (main @ 07f1a6154)
Serve a page that opens a dialog while loading:
<title>T</title><script>alert('hi')</script><h1>Hi</h1>
Then, with a default MCP server (Chromium):
browser_navigate { url: "http://localhost:PORT/" }browser_snapshot {}Repro with the repo's MCP fixtures and timeouts: { navigation: 3000 } to keep it short:
NAV after 4600 ms: ### Error
TimeoutError: browserBackend.callTool: Timeout 3000ms exceeded.
Call log:
- navigating to "http://localhost:PORT/", waiting until "domcontentloaded"
SNAP= ### Error
Error: Tool "browser_snapshot" does not handle the modal state.
### Modal state
- ["alert" dialog with message "hi"]: can be handled by browser_handle_dialog
browser_navigate returns as soon as the dialog opens and reports it in the modal state, the same way browser_click does when a click opens a dialog (see alert dialog w/ race in tests/mcp/dialogs.spec.ts). The agent can then call browser_handle_dialog and continue.
page.goto never reaches domcontentloaded while the dialog is open, so the call blocks for the full navigation timeout (60s by default) and then fails with a TimeoutError. Only after that does the modal state become visible. With the default timeout this is long enough to trip client-side tool timeouts, and one hostile or buggy page stalls the whole server for a minute per navigation.
Tab.navigate() (packages/playwright-core/src/tools/backend/tab.ts) awaits page.goto directly, while other actions go through waitForCompletion, which races the action against TabEvents.modalState (_raceAgainstModalStates). Navigation should use the same race, returning early when a modal state appears.
I intend to work on this and will send a PR.
- Operating System: macOS (Darwin 25.6.0)
- Node.js: 24.8.0
- Browser: Chromium
- Playwright: main @ 07f1a6154
Relay reads this issue against the repository's contribution signals: the files it is likely to touch, how the maintainers triage work this size, and what the first contribution would exercise.
The full analysis for this issue is still being assembled. Until then, the description above and the thread on GitHub are the most reliable context.