microsoft/playwright · error · Error

File paths cannot be mixed with buffers

Error message

File paths cannot be mixed with buffers

What it means

Thrown by convertInputFiles when items contains at least one string (file path) but not every item is a string — i.e. the array mixes string paths with FilePayload (buffer) objects. The path-resolution branch requires all entries to be strings, so a mixed list is rejected before any filesystem access.

Source

Thrown at packages/playwright-core/src/client/elementHandle.ts:287

      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;
          return {
            name: localDirectory ? path.relative(localDirectory, file) : path.basename(file),
            lastModifiedMs
          };
        })),
      }, kNoTimeout), { internal: true });
      for (let i = 0; i < files.length; i++) {
        const writable = WritableStream.from(writableStreams[i]);
        await stream.promises.pipeline(fs.createReadStream(files[i]), writable.stream());

View on GitHub (pinned to c8fc3bf8d3)

Solutions

  1. Use either all string paths or all FilePayload objects in a single call.
  2. Normalize mixed input up front: read disk files into FilePayload buffers, or write buffers to temp files and pass paths.
  3. Split into two setInputFiles calls if the element genuinely needs both (rare).

Example fix

// before
await locator.setInputFiles([
  { name: 'a.txt', mimeType: 'text/plain', buffer: Buffer.from('hi') },
  '/tmp/b.txt',
]);

// after — all buffers
await locator.setInputFiles([
  { name: 'a.txt', mimeType: 'text/plain', buffer: Buffer.from('hi') },
  { name: 'b.txt', mimeType: 'text/plain', buffer: await fs.promises.readFile('/tmp/b.txt') },
]);
Defensive patterns

Strategy: type-guard

Validate before calling

// Normalize a mixed list into either all-paths or all-payloads before setInputFiles.
function normalizeInputFiles(files) {
  const hasString = files.some(f => typeof f === 'string');
  const hasPayload = files.some(f => typeof f === 'object' && f !== null);
  if (hasString && hasPayload)
    throw new Error('File paths cannot be mixed with buffers; choose one form.');
  return files;
}

Type guard

type FilePayload = { name: string; mimeType?: string; buffer: Buffer };
type InputItem = string | FilePayload;
function isPayload(x: InputItem): x is FilePayload { return typeof x === 'object' && x !== null && 'buffer' in x; }
function isPath(x: InputItem): x is string { return typeof x === 'string'; }
function assertUniform(items: InputItem[]): 'paths' | 'payloads' {
  const allPaths = items.every(isPath);
  const allPayloads = items.every(isPayload);
  if (!allPaths && !allPayloads)
    throw new Error('File paths cannot be mixed with buffers');
  return allPaths ? 'paths' : 'payloads';
}

Prevention

When it happens

Trigger: Calling setInputFiles([{ name: 'a.txt', buffer: Buffer.from('...') }, '/tmp/b.txt']) — some entries are FilePayload objects, others are path strings.

Common situations: Building an upload list from mixed sources (some files on disk, some in memory); passing a single-element array where the single element is a payload alongside a path elsewhere; merging user input without normalization.

Related errors


AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12). Data as JSON: /api/errors/9f8bf79c4feee4fa. Report an issue: GitHub.