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

  1. Pass an explicit target (the <input type="file"> element) so setInputFiles is used directly.
  2. Click the upload trigger first, then call upload() immediately so the filechooser is pending when upload runs.
  3. Ensure the page actually uses a native file input; for custom uploaders, use evaluate() to set the file via JS or switch approach.
  4. 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

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


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/ab753e5edb374074. Report an issue: GitHub.