{"record":{"id":"67098ed634448f29","repo":"Budibase/budibase","slug":"invalid-upload-payload","errorCode":null,"errorMessage":"Invalid upload payload","messagePattern":"Invalid upload payload","errorType":"http","errorClass":"HTTPError","httpStatus":400,"severity":"error","filePath":"packages/server/src/api/controllers/ai/files.ts","lineNumber":194,"sourceCode":"  ctx: UserCtx<\n    void,\n    AgentFileUploadResponse,\n    { agentId: string; operationId: string }\n  >\n) {\n  const { agentId, operationId } = ctx.params\n  const upload = normalizeUpload(\n    ctx.request.files?.file ||\n      ctx.request.files?.knowledgeBaseFile ||\n      ctx.request.files?.upload\n  )\n\n  if (!upload) {\n    throw new HTTPError(\"file is required\", 400)\n  }\n  const filePath = upload.filepath || upload.path\n  if (!filePath) {\n    throw new HTTPError(\"Invalid upload payload\", 400)\n  }\n\n  const filename = upload.originalFilename || upload.name || \"agent-document\"\n  const mimetype = upload.mimetype || upload.type\n  const fileSize =\n    typeof upload.size === \"number\"\n      ? upload.size\n      : Number(upload.size) || undefined\n  if (!isKnowledgeFileSupported({ filename, mimetype })) {\n    await unlinkSafe(filePath)\n    throw new HTTPError(\"Unsupported file type for knowledge ingestion\", 400)\n  }\n\n  const buffer = await readFile(filePath)\n\n  try {\n    const updated = await sdk.ai.rag.uploadFileForOperation(\n      agentId,","sourceCodeStart":176,"sourceCodeEnd":212,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/api/controllers/ai/files.ts#L176-L212","documentation":"Thrown when a file entry exists in ctx.request.files but the normalized upload object exposes neither filepath nor path, so the controller cannot locate the temp file on disk. Indicates a malformed or non-standard upload payload shape rather than a missing file.","triggerScenarios":"The multipart parser produced an upload object lacking both filepath and path (e.g. a memoryStorage parser returning a Buffer without a path); custom middleware reshaping ctx.request.files; a client sending form values coerced into 'file' fields instead of real file parts.","commonSituations":"Switching koa-body/busboy options (multipart, memoryStorage) without accounting for the different upload shape; custom normalization middleware dropping fields; using a non-standard parsing library that stores content under different keys.","solutions":["Use the standard multipart parser configuration so uploads expose filepath (tmp-file storage, e.g. formidable defaults).","Inspect the parsed upload object shape and confirm it has filepath or path before the handler runs.","Check middleware ordering so multipart parsing executes before the route handler.","Send a genuine file part (not a text field) named file/knowledgeBaseFile/upload."],"exampleFix":"// before\napp.use(koaBody({ multipart: true }))\n// after\napp.use(koaBody({ multipart: true, formidable: { uploadDir: os.tmpdir(), keepExtensions: true } }))","handlingStrategy":"type-guard","validationCode":"const upload = files?.file || files?.knowledgeBaseFile || files?.upload\nconst filePath = upload?.filepath || upload?.path\nif (!filePath) throw new Error(\"Invalid upload payload\")","typeGuard":"function hasReadablePath(u) {\n  return Boolean(u && typeof u === \"object\" && (typeof u.filepath === \"string\" || typeof u.path === \"string\"))\n}","tryCatchPattern":"try {\n  await uploadAgentFile(ctx)\n} catch (err) {\n  if (err.message === \"Invalid upload payload\") {\n    // inspect parser config / upload object shape\n  } else throw err\n}","preventionTips":["Keep the standard multipart parser with tmp-file storage so uploads expose filepath.","Do not insert custom middleware that reshapes ctx.request.files.","Log the parsed upload object once when upgrading parsing libraries.","Send real file parts, not coerced text fields."],"tags":["http-400","file-upload","payload-shape"],"backgroundTag":"invalid-upload-payload","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}