{"record":{"id":"7c1c47b771bf85c5","repo":"can1357/oh-my-pi","slug":"tab-uploadfile-requires-at-least-one-file-path","errorCode":null,"errorMessage":"tab.uploadFile() requires at least one file path","messagePattern":"tab\\.uploadFile\\(\\) requires at least one file path","errorType":"validation","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/browser/cmux/cmux-tab.ts","lineNumber":716,"sourceCode":"\t\t\t\tconst dispatch = (type, point) => target.dispatchEvent(new MouseEvent(type, {\n\t\t\t\t\tbubbles: true,\n\t\t\t\t\tcancelable: true,\n\t\t\t\t\tview: window,\n\t\t\t\t\tclientX: point.x,\n\t\t\t\t\tclientY: point.y,\n\t\t\t\t\tbuttons: type === \"mouseup\" ? 0 : 1,\n\t\t\t\t}));\n\t\t\t\tdispatch(\"mousemove\", points.start);\n\t\t\t\tdispatch(\"mousedown\", points.start);\n\t\t\t\tdispatch(\"mousemove\", points.end);\n\t\t\t\tdispatch(\"mouseup\", points.end);\n\t\t\t\treturn true;\n\t\t\t})()`,\n\t\t);\n\t}\n\n\tasync uploadFile(selector: string, ...filePaths: string[]): Promise<void> {\n\t\tif (!filePaths.length) throw new ToolError(\"tab.uploadFile() requires at least one file path\");\n\t\tconst files: FilePayload[] = [];\n\t\tfor (const filePath of filePaths) {\n\t\t\tconst absolute = resolveToCwd(filePath, this.#requireRunContext(\"tab.uploadFile()\").session.cwd);\n\t\t\tconst file = Bun.file(absolute);\n\t\t\tconst data = Buffer.from(await file.arrayBuffer()).toString(\"base64\");\n\t\t\tfiles.push({ name: path.basename(absolute), type: file.type || \"application/octet-stream\", data });\n\t\t}\n\t\tawait this.#selectorAction(selector, \"uploadFile\", { files });\n\t}\n\n\tasync waitForResponse(\n\t\tpattern: string | RegExp | ((response: CmuxResponse) => boolean | Promise<boolean>),\n\t\topts?: { timeout?: number },\n\t): Promise<CmuxResponse> {\n\t\tconst timeoutMs = opts?.timeout ?? this.#runContext?.timeoutMs ?? 30_000;\n\t\tconst signal = this.#runContext?.signal;\n\t\tawait this.#installResponseObserver();\n\t\tconst startId = await this.#responseCursor();","sourceCodeStart":698,"sourceCodeEnd":734,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/browser/cmux/cmux-tab.ts#L698-L734","documentation":"CmuxTab.uploadFile(selector, ...filePaths) is a variadic API that base64-encodes each path and ships the payloads to the cmux daemon. It throws this ToolError synchronously when zero file paths are supplied, because the underlying browser.uploadFile request would have nothing to set.","triggerScenarios":"Calling tab.uploadFile('#input') with no path arguments — typically when the caller's file list came from an empty array spread (tab.uploadFile(selector, ...files)) or from a variable that was undefined/empty.","commonSituations":"Spreading a dynamically collected file list that the collection step failed to populate; tool/agent code passing an optional files parameter straight through; refactoring from a single-path signature to variadic and dropping the argument.","solutions":["Pass at least one file path: tab.uploadFile(selector, \"/path/to/file.png\").","Guard the call site: check files.length > 0 before invoking uploadFile.","If zero files is a legitimate state, skip the upload (or clear the input with tab.evaluate) instead of calling uploadFile.","Verify the file-collection step actually produced paths (log/validate the array before spreading)."],"exampleFix":"// before: spreads possibly-empty array\nawait tab.uploadFile(\"#avatar\", ...filePaths);\n// after: guard the empty case\nif (filePaths.length === 0) throw new Error(\"no files to upload\");\nawait tab.uploadFile(\"#avatar\", ...filePaths);","handlingStrategy":"validation","validationCode":"if (!Array.isArray(filePaths) || filePaths.length === 0) {\n  throw new Error(\"uploadFile needs at least one file path\");\n}","typeGuard":"function hasFiles(paths: unknown): paths is [string, ...string[]] {\n  return Array.isArray(paths) && paths.length > 0 && typeof paths[0] === \"string\";\n}","tryCatchPattern":null,"preventionTips":["Validate file lists at the source before spreading into variadic calls","Give uploadFile parameters a non-empty tuple type [string, ...string[]]","Skip or clear the file input explicitly when zero files is a valid state","Avoid passing optional/possibly-undefined path arrays straight into the call"],"tags":["browser","argument-validation","file-upload"],"backgroundTag":"missing-required-argument","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}