microsoft/playwright · error · Error

Cannot transfer files larger than 50Mb to a browser not co-l

Error message

Cannot transfer files larger than 50Mb to a browser not co-located with the server

What it means

When the browser is not collocated with the Playwright server and localPaths are used, files are read into memory buffers to ship across the boundary. If their combined size meets or exceeds 50 MiB (fileUploadSizeLimit) the upload is refused to avoid exhausting memory.

Source

Thrown at packages/playwright-core/src/server/fileUploadUtils.ts:66

    localDirectory = (directoryStream as WritableStreamDispatcher).path();

  if (localPaths) {
    for (const p of localPaths)
      assert(path.isAbsolute(p) && path.resolve(p) === p, 'Paths provided to localPaths must be absolute and fully resolved.');
  }

  let fileBuffers: {
    name: string,
    mimeType?: string,
    buffer: Buffer,
    lastModifiedMs?: number,
  }[] | undefined = payloads;

  if (!frame._page.browserContext._browser._isBrowserCollocatedWithServer) {
    // If the browser is on a different machine read files into buffers.
    if (localPaths) {
      if (await filesExceedUploadLimit(localPaths))
        throw new Error('Cannot transfer files larger than 50Mb to a browser not co-located with the server');
      fileBuffers = await Promise.all(localPaths.map(async item => {
        return {
          name: path.basename(item),
          buffer: await fs.promises.readFile(item),
          lastModifiedMs: (await fs.promises.stat(item)).mtimeMs,
        };
      }));
      localPaths = undefined;
    }
  }

  const filePayloads: types.FilePayload[] | undefined = fileBuffers?.map(payload => ({
    name: payload.name,
    mimeType: payload.mimeType || mime.getType(payload.name) || 'application/octet-stream',
    buffer: payload.buffer.toString('base64'),
    lastModifiedMs: payload.lastModifiedMs
  }));

View on GitHub (pinned to c8fc3bf8d3)

Solutions

  1. Switch to streaming uploads via a writable stream when available to avoid the in-memory cap.
  2. Reduce the per-call payload below 50 MiB (split into multiple calls or trim fixtures).
  3. Run the browser collocated with the server so the 50 MiB transfer limit does not apply.
  4. Compress or sample the test data so the fixture stays under the limit.

Example fix

// before: 60 MiB file against remote browser -> throws
await handle.setInputFiles('/data/big.mov');
// after: stream instead, or shrink fixture
await handle.setInputFiles('/data/small.mov');
Defensive patterns

Strategy: validation

Validate before calling

const fs = require('fs');
const LIMIT = 50 * 1024 * 1024;
async function totalSize(paths: string[]) {
  return (await Promise.all(paths.map(p => fs.promises.stat(p).then(s => s.size)))).reduce((a,b)=>a+b,0);
}
if (await totalSize(paths) >= LIMIT) throw new Error('over 50MiB');

Type guard

null

Try / catch

null

Prevention

When it happens

Trigger: Calling setInputFiles(paths) where the total size of all listed files is >= 50 MiB, while _isBrowserCollocatedWithServer is false (remote browser / separate browser server host). filesExceedUploadLimit sums fs.stat sizes.

Common situations: Uploading large media, PDFs, archives, or datasets in CI against a remote browser service; batch uploads of many files whose total crosses 50 MiB; test fixtures with oversized attachments.

Related errors


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