{"record":{"id":"6ab899783f49e053","repo":"microsoft/playwright","slug":"no-file-chooser-visible","errorCode":null,"errorMessage":"No file chooser visible","messagePattern":"No file chooser visible","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/playwright-core/src/tools/backend/files.ts","lineNumber":40,"sourceCode":"export const uploadFile = defineTabTool({\n  capability: 'core',\n\n  schema: {\n    name: 'browser_file_upload',\n    title: 'Upload files',\n    description: 'Upload one or multiple files',\n    inputSchema: z.object({\n      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.'),\n    }),\n    type: 'action',\n  },\n\n  handle: async (tab, params, response) => {\n    response.setIncludeSnapshot();\n\n    const modalState = tab.modalStates().find(state => state.type === 'fileChooser');\n    if (!modalState)\n      throw new Error('No file chooser visible');\n\n    if (params.paths)\n      await Promise.all(params.paths.map(filePath => response.resolveClientFilename(filePath)));\n\n    response.addCode(`await fileChooser.setFiles(${JSON.stringify(params.paths)})`);\n\n    tab.clearModalState(modalState);\n    await tab.waitForCompletion(async () => {\n      if (params.paths)\n        await modalState.fileChooser.setFiles(params.paths);\n    });\n  },\n\n  clearsModalState: 'fileChooser',\n});\n\nexport const drop = defineTabTool({\n  capability: 'core',","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/microsoft/playwright/blob/c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6/packages/playwright-core/src/tools/backend/files.ts#L22-L58","documentation":"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.","triggerScenarios":"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.","commonSituations":"Agent uploads before clicking the upload button; chooser opened in a different tab than currentTab; the chooser closed because the page navigated.","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)."],"exampleFix":"// before\nawait client.callTool('browser_file_upload', { paths: ['/x.pdf'] }); // no chooser -> throws\n\n// after\nawait client.callTool('browser_click', { element: 'Upload', ref: 'e3' });\nawait page.waitForEvent('filechooser');\nawait client.callTool('browser_file_upload', { paths: ['/abs/x.pdf'] });","handlingStrategy":"validation","validationCode":"const hasChooser = tab.modalStates().some(s => s.type === 'fileChooser');\nif (hasChooser) {\n  await client.callTool('browser_file_upload', { paths: ['/abs/file'] });\n}","typeGuard":"function isFileChooserModal(s: ModalState): boolean {\n  return s.type === 'fileChooser';\n}","tryCatchPattern":"try {\n  await client.callTool('browser_file_upload', { paths });\n} catch (e) {\n  if (e instanceof Error && e.message === 'No file chooser visible') {\n    // re-click the upload trigger and wait for filechooser, then retry\n  } else throw e;\n}","preventionTips":["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."],"tags":["file-chooser","modal-state","mcp-tool","synchronization"],"backgroundTag":null,"analyzedSha":"c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6","analyzedAt":"2026-08-12T07:26:36.950Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}