{"record":{"id":"9f8bf79c4feee4fa","repo":"microsoft/playwright","slug":"file-paths-cannot-be-mixed-with-buffers","errorCode":null,"errorMessage":"File paths cannot be mixed with buffers","messagePattern":"File paths cannot be mixed with buffers","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/playwright-core/src/client/elementHandle.ts","lineNumber":287,"sourceCode":"      if (localDirectory)\n        throw new Error('Multiple directories are not supported');\n      localDirectory = path.resolve(item as string);\n    } else {\n      localPaths ??= [];\n      localPaths.push(path.resolve(item as string));\n    }\n  }\n  if (localPaths?.length && localDirectory)\n    throw new Error('File paths must be all files or a single directory');\n  return [localPaths, localDirectory];\n}\n\nexport async function convertInputFiles(files: string | FilePayload | string[] | FilePayload[], context: BrowserContext): Promise<SetInputFilesFiles> {\n  const items: (string | FilePayload)[] = Array.isArray(files) ? files.slice() : [files];\n\n  if (items.some(item => typeof item === 'string')) {\n    if (!items.every(item => typeof item === 'string'))\n      throw new Error('File paths cannot be mixed with buffers');\n\n    const [localPaths, localDirectory] = await resolvePathsAndDirectoryForInputFiles(items);\n\n    if (context._connection.isRemote()) {\n      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!;\n      const { writableStreams, rootDir } = await context._wrapApiCall(async () => context._channel.createTempFiles({\n        rootDirName: localDirectory ? path.basename(localDirectory) : undefined,\n        items: await Promise.all(files.map(async file => {\n          const lastModifiedMs = (await fs.promises.stat(file)).mtimeMs;\n          return {\n            name: localDirectory ? path.relative(localDirectory, file) : path.basename(file),\n            lastModifiedMs\n          };\n        })),\n      }, kNoTimeout), { internal: true });\n      for (let i = 0; i < files.length; i++) {\n        const writable = WritableStream.from(writableStreams[i]);\n        await stream.promises.pipeline(fs.createReadStream(files[i]), writable.stream());","sourceCodeStart":269,"sourceCodeEnd":305,"githubUrl":"https://github.com/microsoft/playwright/blob/c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6/packages/playwright-core/src/client/elementHandle.ts#L269-L305","documentation":"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.","triggerScenarios":"Calling setInputFiles([{ name: 'a.txt', buffer: Buffer.from('...') }, '/tmp/b.txt']) — some entries are FilePayload objects, others are path strings.","commonSituations":"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.","solutions":["Use either all string paths or all FilePayload objects in a single call.","Normalize mixed input up front: read disk files into FilePayload buffers, or write buffers to temp files and pass paths.","Split into two setInputFiles calls if the element genuinely needs both (rare)."],"exampleFix":"// before\nawait locator.setInputFiles([\n  { name: 'a.txt', mimeType: 'text/plain', buffer: Buffer.from('hi') },\n  '/tmp/b.txt',\n]);\n\n// after — all buffers\nawait locator.setInputFiles([\n  { name: 'a.txt', mimeType: 'text/plain', buffer: Buffer.from('hi') },\n  { name: 'b.txt', mimeType: 'text/plain', buffer: await fs.promises.readFile('/tmp/b.txt') },\n]);","handlingStrategy":"type-guard","validationCode":"// Normalize a mixed list into either all-paths or all-payloads before setInputFiles.\nfunction normalizeInputFiles(files) {\n  const hasString = files.some(f => typeof f === 'string');\n  const hasPayload = files.some(f => typeof f === 'object' && f !== null);\n  if (hasString && hasPayload)\n    throw new Error('File paths cannot be mixed with buffers; choose one form.');\n  return files;\n}","typeGuard":"type FilePayload = { name: string; mimeType?: string; buffer: Buffer };\ntype InputItem = string | FilePayload;\nfunction isPayload(x: InputItem): x is FilePayload { return typeof x === 'object' && x !== null && 'buffer' in x; }\nfunction isPath(x: InputItem): x is string { return typeof x === 'string'; }\nfunction assertUniform(items: InputItem[]): 'paths' | 'payloads' {\n  const allPaths = items.every(isPath);\n  const allPayloads = items.every(isPayload);\n  if (!allPaths && !allPayloads)\n    throw new Error('File paths cannot be mixed with buffers');\n  return allPaths ? 'paths' : 'payloads';\n}","tryCatchPattern":null,"preventionTips":["Pick one representation (paths or payloads) up front and stick to it.","Read disk files into buffers only if you also convert all other entries.","Validate uniformity before the API call."],"tags":["file-upload","validation","input-files"],"backgroundTag":null,"analyzedSha":"c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6","analyzedAt":"2026-08-12T07:26:36.950Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}