n8n-io/n8n · error · Error
No file chooser pending and no element target provided
Error message
No file chooser pending and no element target provided
What it means
Thrown by the Playwright adapter's upload() when there is no pending file-chooser dialog AND no element target was provided. upload() first checks state.pendingFileChooser (set when a page raised a file chooser event); if none is pending, it requires a target to call locator.setInputFiles on. Without either, it cannot decide where to send the files.
Source
Thrown at packages/@n8n/mcp-browser/src/adapters/playwright.ts:457
const amount = options?.amount ?? 500;
const delta = options?.direction === 'up' ? -amount : amount;
await page.mouse.wheel(0, delta);
}
}
async upload(pageId: string, target: ElementTarget | undefined, files: string[]): Promise<void> {
const state = await this.ensurePage(pageId);
// If a file chooser dialog is pending, use it directly
if (state.pendingFileChooser) {
await state.pendingFileChooser.setFiles(files);
state.pendingFileChooser = undefined;
return;
}
// Otherwise, set files on the input element
if (!target) {
throw new Error('No file chooser pending and no element target provided');
}
const locator = await this.resolveLocator(pageId, target);
await locator.setInputFiles(files);
}
async dialog(pageId: string, action: 'accept' | 'dismiss', text?: string): Promise<string> {
const state = await this.ensurePage(pageId);
// If a dialog is already pending, handle it immediately
if (state.pendingDialog) {
const dialogType = state.pendingDialog.type();
if (action === 'accept') {
await state.pendingDialog.accept(text);
} else {
await state.pendingDialog.dismiss();
}
state.pendingDialog = undefined;
return dialogType;View on GitHub (pinned to 5ac6606e81)
Solutions
- Pass an explicit target (the <input type="file"> element) so setInputFiles is used directly.
- Click the upload trigger first, then call upload() immediately so the filechooser is pending when upload runs.
- Ensure the page actually uses a native file input; for custom uploaders, use evaluate() to set the file via JS or switch approach.
- Do not call upload() twice without a new chooser — the first call clears pendingFileChooser.
Example fix
// before — no chooser pending, no target
await adapter.upload(pageId, undefined, ['/tmp/file.csv']);
// throws
// after — click trigger then upload, OR pass the input target
await adapter.click(pageId, { ref: '@uploadBtn' }); // triggers chooser
await adapter.upload(pageId, undefined, ['/tmp/file.csv']); // chooser now pending
// OR pass the input directly
await adapter.upload(pageId, { ref: '@fileInput' }, ['/tmp/file.csv']); Defensive patterns
Strategy: validation
Validate before calling
function canUpload(state: { pendingFileChooser?: unknown }, target?: unknown): boolean {
return Boolean(state.pendingFileChooser) || Boolean(target);
} Type guard
function hasUploadTargetOrChooser(state: { pendingFileChooser?: unknown }, target?: unknown): boolean {
return Boolean(state.pendingFileChooser) || Boolean(target);
} Prevention
- Pass an explicit input element target when no native file chooser is expected.
- Click the upload trigger immediately before upload() so the chooser is pending.
- Do not call upload() twice on the same chooser — the first call clears it.
When it happens
Trigger: Calling playwrightAdapter.upload(pageId, target, files) where target is undefined and state.pendingFileChooser is undefined (no recent file-chooser event on the page). The caller expected a chooser to be pending but none was captured, and provided no fallback input element target.
Common situations: The caller clicked an upload button expecting a native file chooser, but the page used a custom (non-input) uploader so no filechooser event fired; the pendingFileChooser was already consumed by a previous upload call; the file chooser event fired on a different pageId; timing — the chooser fired before upload() was called and was cleared.
Related errors
- Invalid ${role}: argument cannot start with '-' (got: ${JSON
- Operation not supported: upload
- No executable path for ${browser}
- Cannot decrease maxIterations when resuming a run. Expected
- Checkpoint for runId ${this.runId} has pending tool calls —
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/ab753e5edb374074.
Report an issue: GitHub.