microsoft/playwright · error · Error
File paths must be all files or a single directory
Error message
File paths must be all files or a single directory
What it means
Thrown by resolvePathsAndDirectoryForInputFiles after the loop, when at least one file path (localPaths) and one directory path (localDirectory) were collected together. setInputFiles requires the list to be all files OR exactly one directory — mixing is not allowed.
Source
Thrown at packages/playwright-core/src/client/elementHandle.ts:278
return payloads.reduce((size, item) => size + (item.buffer ? item.buffer.byteLength : 0), 0) >= fileUploadSizeLimit;
}
async function resolvePathsAndDirectoryForInputFiles(items: string[]): Promise<[string[] | undefined, string | undefined]> {
let localPaths: string[] | undefined;
let localDirectory: string | undefined;
for (const item of items) {
const stat = await fs.promises.stat(item as string);
if (stat.isDirectory()) {
if (localDirectory)
throw new Error('Multiple directories are not supported');
localDirectory = path.resolve(item as string);
} else {
localPaths ??= [];
localPaths.push(path.resolve(item as string));
}
}
if (localPaths?.length && localDirectory)
throw new Error('File paths must be all files or a single directory');
return [localPaths, localDirectory];
}
export async function convertInputFiles(files: string | FilePayload | string[] | FilePayload[], context: BrowserContext): Promise<SetInputFilesFiles> {
const items: (string | FilePayload)[] = Array.isArray(files) ? files.slice() : [files];
if (items.some(item => typeof item === 'string')) {
if (!items.every(item => typeof item === 'string'))
throw new Error('File paths cannot be mixed with buffers');
const [localPaths, localDirectory] = await resolvePathsAndDirectoryForInputFiles(items);
if (context._connection.isRemote()) {
const files = localDirectory ? (await fs.promises.readdir(localDirectory, { withFileTypes: true, recursive: true })).filter(f => f.isFile()).map(f => path.join(f.parentPath, f.name)) : localPaths!;
const { writableStreams, rootDir } = await context._wrapApiCall(async () => context._channel.createTempFiles({
rootDirName: localDirectory ? path.basename(localDirectory) : undefined,
items: await Promise.all(files.map(async file => {
const lastModifiedMs = (await fs.promises.stat(file)).mtimeMs;View on GitHub (pinned to c8fc3bf8d3)
Solutions
- Split the call: upload files in one setInputFiles, the directory in another (or in a separate operation).
- Expand the directory to explicit file paths and pass only files.
- Pre-validate the list so it is either all-files or exactly-one-directory.
Example fix
// before
await locator.setInputFiles(['a.txt', './folder']);
// after — files only
const { readdirSync, statSync } = require('node:fs');
const { join } = require('node:path');
const expand = d => readdirSync(d).flatMap(f => { const p = join(d,f); return statSync(p).isDirectory() ? expand(p) : [p]; });
await locator.setInputFiles(['a.txt', ...expand('./folder')]); Defensive patterns
Strategy: validation
Validate before calling
import { statSync } from 'node:fs';
function validateInputPaths(items: string[]) {
let files = 0, dirs = 0;
for (const p of items) { try { if (statSync(p).isDirectory()) dirs++; else files++; } catch {} }
if (files > 0 && dirs > 0) throw new Error('Pass either all files or exactly one directory; mixing is not supported.');
if (dirs > 1) throw new Error('At most one directory is supported.');
return items;
} Type guard
import { statSync } from 'node:fs';
type InputList = { kind: 'files'; paths: string[] } | { kind: 'directory'; path: string };
function classify(items: string[]): InputList {
const files: string[] = [];
const dirs: string[] = [];
for (const p of items) { try { (statSync(p).isDirectory() ? dirs : files).push(p); } catch {} }
if (dirs.length > 1) throw new Error('Multiple directories not supported');
if (files.length && dirs.length) throw new Error('Files and a directory cannot be mixed');
return dirs.length ? { kind: 'directory', path: dirs[0] } : { kind: 'files', paths: files };
} Prevention
- Classify each path (file vs dir) before building the upload list.
- Expand directories to explicit file paths to keep the call uniform.
- Reject mixed input early with a clear error.
When it happens
Trigger: Passing an array that contains both regular files and a directory, e.g. setInputFiles(['a.txt', 'b.png', './folder']). The per-item directory check sets localDirectory, files populate localPaths, and the post-loop mix check fires.
Common situations: Glob results that include both files and a folder; user assembling uploads from disparate sources; expecting the directory to be uploaded alongside individual files.
Related errors
- Multiple directories are not supported
- File paths cannot be mixed with buffers
- Exactly one of payloads, localPaths and streams must be prov
- Cannot set buffer larger than 50Mb, please write it to a fil
- localPaths are not allowed when the client is not local
AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12).
Data as JSON: /api/errors/8988179baa4df9bf.
Report an issue: GitHub.