microsoft/playwright · error · Error

No dialog visible

Error message

No dialog visible

What it means

Thrown by the browser_handle_dialog tool when tab.modalStates() contains no entry with type === 'dialog'. The tool is only valid while a JS dialog (alert/confirm/prompt/beforeunload) is currently pending on the tab.

Source

Thrown at packages/playwright-core/src/tools/backend/dialogs.ts:37

export const handleDialog = defineTabTool({
  capability: 'core',

  schema: {
    name: 'browser_handle_dialog',
    title: 'Handle a dialog',
    description: 'Handle a dialog',
    inputSchema: z.object({
      accept: z.boolean().describe('Whether to accept the dialog.'),
      promptText: z.string().optional().describe('The text of the prompt in case of a prompt dialog.'),
    }),
    type: 'action',
  },

  handle: async (tab, params, response) => {
    const dialogState = tab.modalStates().find(state => state.type === 'dialog');
    if (!dialogState)
      throw new Error('No dialog visible');

    tab.clearModalState(dialogState);
    await tab.waitForCompletion(async () => {
      if (params.accept)
        await dialogState.dialog.accept(params.promptText);
      else
        await dialogState.dialog.dismiss();
    });
  },

  clearsModalState: 'dialog',
});

export default [
  handleDialog,
];

View on GitHub (pinned to c8fc3bf8d3)

Solutions

  1. Register a dialog listener and only invoke the tool while the dialog state is present.
  2. Use page.waitForEvent('dialog') (or tab.waitForCompletion) to synchronize before handling.
  3. Re-snapshot the tab modal states and skip the call when none of type 'dialog' exist.

Example fix

// before
await client.callTool('browser_handle_dialog', { accept: true }); // throws if no dialog

// after
page.on('dialog', async d => {
  await client.callTool('browser_handle_dialog', { accept: true, promptText: d.defaultValue() });
});
Defensive patterns

Strategy: validation

Validate before calling

// Only call the tool while a dialog modal state exists.
const states = tab.modalStates();
const hasDialog = states.some(s => s.type === 'dialog');
if (hasDialog) {
  await client.callTool('browser_handle_dialog', { accept: true });
}

Type guard

import type { ModalState } from './tab';
function isDialogModal(s: ModalState): boolean {
  return s.type === 'dialog';
}

Try / catch

try {
  await client.callTool('browser_handle_dialog', { accept: true });
} catch (e) {
  if (e instanceof Error && e.message === 'No dialog visible') {
    // not actually an error in your flow; ignore
  } else throw e;
}

Prevention

When it happens

Trigger: Calling browser_handle_dialog when no dialog event has fired, or after the dialog was already cleared (clearModalState was invoked, e.g. by a previous handle call or auto-dismiss).

Common situations: Agent proactively calling handle-dialog 'just in case'; race where the dialog was dismissed by page navigation before the tool ran; missed the page.on('dialog') listener registration.

Related errors


AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12). Data as JSON: /api/errors/a54b3eeb8598697f. Report an issue: GitHub.