{"record":{"id":"ed66b47457c72768","repo":"microsoft/playwright","slug":"localpaths-are-not-allowed-when-the-client-is-not","errorCode":null,"errorMessage":"localPaths are not allowed when the client is not local","messagePattern":"localPaths are not allowed when the client is not local","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/playwright-core/src/server/fileUploadUtils.ts","lineNumber":40,"sourceCode":"import type { WritableStreamDispatcher } from './dispatchers/writableStreamDispatcher';\nimport type { InputFilesItems } from './dom';\nimport type { Frame } from './frames';\nimport type * as types from './types';\nimport type * as channels from './channels';\n\n// Keep in sync with the client.\nexport const fileUploadSizeLimit = 50 * 1024 * 1024;\n\nasync function filesExceedUploadLimit(files: string[]) {\n  const sizes = await Promise.all(files.map(async file => (await fs.promises.stat(file)).size));\n  return sizes.reduce((total, size) => total + size, 0) >= fileUploadSizeLimit;\n}\n\nexport async function prepareFilesForUpload(frame: Frame, params: Omit<channels.ElementHandleSetInputFilesParams, 'timeout'>): Promise<InputFilesItems> {\n  const { payloads, streams, directoryStream } = params;\n  let { localPaths, localDirectory } = params;\n  if (localPaths && !frame.attribution.playwright.options.isClientCollocatedWithServer)\n    throw new Error('localPaths are not allowed when the client is not local');\n\n  if ([payloads, localPaths, localDirectory, streams, directoryStream].filter(Boolean).length !== 1)\n    throw new Error('Exactly one of payloads, localPaths and streams must be provided');\n\n  if (streams)\n    localPaths = streams.map(c => (c as WritableStreamDispatcher).path());\n  if (directoryStream)\n    localDirectory = (directoryStream as WritableStreamDispatcher).path();\n\n  if (localPaths) {\n    for (const p of localPaths)\n      assert(path.isAbsolute(p) && path.resolve(p) === p, 'Paths provided to localPaths must be absolute and fully resolved.');\n  }\n\n  let fileBuffers: {\n    name: string,\n    mimeType?: string,\n    buffer: Buffer,","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/microsoft/playwright/blob/c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6/packages/playwright-core/src/server/fileUploadUtils.ts#L22-L58","documentation":"prepareFilesForUpload rejects localPaths (filesystem paths) when the Playwright client and server are not collocated - i.e. when isClientCollocatedWithServer is false, which happens in remote/browser-server deployments where the file system the user sees differs from the server's.","triggerScenarios":"Calling element.setInputFiles(paths) with absolute filesystem paths while connected to a remote Playwright server or browser server (playwright.chromium.launchServer / connectOverCDP / ws endpoint) where the client machine is not the server machine.","commonSituations":"Running tests against a remote browser service; connecting via websockets to a separately-launched browser server; containerized drivers where client and server differ; misconfigured CI pointing at a remote endpoint while passing local developer-machine paths.","solutions":["Switch to setInputFiles with file payloads (read the file into a Buffer) so the bytes travel over the wire.","Or use streams via the writable-stream channel when supported.","Ensure the file actually exists on the server if you intend to keep paths, then run collocated.","If you did not mean to run remotely, drop the wsEndpoint/server config so client and server are the same process."],"exampleFix":"// before (remote server)\nawait handle.setInputFiles('/Users/me/file.pdf'); // throws\n// after: send the bytes\nconst fs = require('fs');\nawait handle.setInputFiles({\n  name: 'file.pdf',\n  mimeType: 'application/pdf',\n  buffer: fs.readFileSync('/Users/me/file.pdf'),\n});","handlingStrategy":"validation","validationCode":"// Decide path vs payload based on collocation\nconst remote = !!process.env.PLAYWRIGHT_WS_ENDPOINT;\nif (remote) {\n  await handle.setInputFiles({ name, mimeType, buffer: fs.readFileSync(localPath) });\n} else {\n  await handle.setInputFiles(localPath);\n}","typeGuard":"// Heuristic: are we talking to a remote server?\nfunction shouldUsePayload() { return !!browser._endpoint && !browser._isCollocated; }","tryCatchPattern":"null","preventionTips":["When connecting to a remote endpoint, always pass file payloads, never paths.","Document in test setup whether the run is local or remote."],"tags":["file-upload","remote","input-files"],"backgroundTag":null,"analyzedSha":"c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6","analyzedAt":"2026-08-12T07:26:36.950Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}