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
- Drive the upload as: click the element that opens the chooser, then immediately call the upload tool within the chooser's lifetime.
- Use page.waitForEvent('filechooser') to gate the call.
- 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
- Always click the chooser-opening element first and await page.waitForEvent('filechooser').
- Keep the chooser interaction in the same turn as the click that opened it.
- Pass absolute paths; the tool resolves client filenames via response.resolveClientFilename.
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
- No dialog visible
- Video recording has already been started.
- Invalid location "${params.location}", expected format is <f
- At least one of "paths" or "data" must be provided.
- fullPage cannot be used with element screenshots.
AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12).
Data as JSON: /api/errors/6ab899783f49e053.
Report an issue: GitHub.