microsoft/playwright · error · Error

No file chooser visible

Error message

No file chooser visible

What it means

Thrown by the file-upload MCP tool when tab.modalStates() has no entry of type 'fileChooser'. The tool can only set files while a <input type=file> chooser (or DOM file chooser) is currently open on the tab.

Source

Thrown at packages/playwright-core/src/tools/backend/files.ts:40

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

  schema: {
    name: 'browser_file_upload',
    title: 'Upload files',
    description: 'Upload one or multiple files',
    inputSchema: z.object({
      paths: z.array(z.string()).optional().describe('The absolute paths to the files to upload. Can be single file or multiple files. If omitted, file chooser is cancelled.'),
    }),
    type: 'action',
  },

  handle: async (tab, params, response) => {
    response.setIncludeSnapshot();

    const modalState = tab.modalStates().find(state => state.type === 'fileChooser');
    if (!modalState)
      throw new Error('No file chooser visible');

    if (params.paths)
      await Promise.all(params.paths.map(filePath => response.resolveClientFilename(filePath)));

    response.addCode(`await fileChooser.setFiles(${JSON.stringify(params.paths)})`);

    tab.clearModalState(modalState);
    await tab.waitForCompletion(async () => {
      if (params.paths)
        await modalState.fileChooser.setFiles(params.paths);
    });
  },

  clearsModalState: 'fileChooser',
});

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

View on GitHub (pinned to c8fc3bf8d3)

Solutions

  1. Drive the upload as: click the element that opens the chooser, then immediately call the upload tool within the chooser's lifetime.
  2. Use page.waitForEvent('filechooser') to gate the call.
  3. To cancel an open chooser intentionally, call the tool with paths omitted (it still requires the modal state to exist).

Example fix

// before
await client.callTool('browser_file_upload', { paths: ['/x.pdf'] }); // no chooser -> throws

// after
await client.callTool('browser_click', { element: 'Upload', ref: 'e3' });
await page.waitForEvent('filechooser');
await client.callTool('browser_file_upload', { paths: ['/abs/x.pdf'] });
Defensive patterns

Strategy: validation

Validate before calling

const hasChooser = tab.modalStates().some(s => s.type === 'fileChooser');
if (hasChooser) {
  await client.callTool('browser_file_upload', { paths: ['/abs/file'] });
}

Type guard

function isFileChooserModal(s: ModalState): boolean {
  return s.type === 'fileChooser';
}

Try / catch

try {
  await client.callTool('browser_file_upload', { paths });
} catch (e) {
  if (e instanceof Error && e.message === 'No file chooser visible') {
    // re-click the upload trigger and wait for filechooser, then retry
  } else throw e;
}

Prevention

When it happens

Trigger: Calling the upload tool without a preceding filechooser event; the chooser was already dismissed; the click that was supposed to open it targeted a non-chooser element.

Common situations: Agent uploads before clicking the upload button; chooser opened in a different tab than currentTab; the chooser closed because the page navigated.

Related errors


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