{"record":{"id":"2a7f0a7bb8698746","repo":"Budibase/budibase","slug":"attempted-to-upload-a-file-without-a-path","errorCode":null,"errorMessage":"Attempted to upload a file without a path","messagePattern":"Attempted to upload a file without a path","errorType":"http","errorClass":"BadRequestError","httpStatus":400,"severity":"error","filePath":"packages/server/src/api/controllers/static/index.ts","lineNumber":269,"sourceCode":"  const file = ctx.request?.files?.file\n  if (!file) {\n    throw new BadRequestError(\"No file provided\")\n  }\n\n  let files = file && Array.isArray(file) ? Array.from(file) : [file]\n\n  ctx.body = await Promise.all(\n    files.map(async file => {\n      const fileName = getUploadFilename(file)\n      const filePath = getUploadPath(file)\n      const rawMimeType = getUploadMimeType(file)\n      if (!fileName) {\n        throw new BadRequestError(\n          \"Attempted to upload a file without a filename\"\n        )\n      }\n      if (!filePath) {\n        throw new BadRequestError(\"Attempted to upload a file without a path\")\n      }\n\n      const extension = [...fileName.split(\".\")].pop()\n      if (!extension) {\n        throw new BadRequestError(\n          `File \"${fileName}\" has no extension, an extension is required to upload a file`\n        )\n      }\n\n      const extensionLower = extension.toLowerCase()\n      const isPublicUser =\n        ctx.roleId === roles.BUILTIN_ROLE_IDS.PUBLIC ||\n        ctx.user?.roleId === roles.BUILTIN_ROLE_IDS.PUBLIC\n      const enforceInvalidExtension = isPublicUser || !env.SELF_HOSTED\n      if (\n        enforceInvalidExtension &&\n        InvalidFileExtensions.includes(extensionLower)\n      ) {","sourceCodeStart":251,"sourceCodeEnd":287,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/api/controllers/static/index.ts#L251-L287","documentation":"Thrown by uploadFile when getUploadPath returns falsy for the uploaded part, i.e. the upload middleware produced no temporary file path to read the content from. The server cannot store a file it cannot locate on disk.","triggerScenarios":"Multipart part arrived without file content (empty part), or the upload middleware (e.g. koa-body/busboy) did not write a temp file because the part was malformed or truncated.","commonSituations":"Interrupted/aborted uploads, oversized bodies rejected before write, misconfigured body parser limits, or sending a part with metadata but zero bytes.","solutions":["Resend the upload ensuring the file part includes actual content","Raise the server/proxy body size limits if large files are being dropped","Verify the multipart boundary and part structure from the client"],"exampleFix":"// before\nfd.append('file', emptyBlob, 'x.png')  // 0 bytes\n// after\nfd.append('file', fileFromDisk, 'x.png')","handlingStrategy":"validation","validationCode":"function uploadHasContent(file) {\n  return Boolean(file && file.size > 0 && file.path !== undefined)\n}","typeGuard":"const hasUploadPath = (f: unknown): f is { path: string } =>\n  typeof f === 'object' && f !== null && typeof (f as any).path === 'string' && (f as any).path.length > 0","tryCatchPattern":"try {\n  await api.uploadFile(fd)\n} catch (err) {\n  if (err instanceof BadRequestError && err.message.includes('without a path')) {\n    // resend with a complete, non-empty file part\n  } else throw err\n}","preventionTips":["Verify the file reads fully from disk before uploading (size > 0)","Raise client/proxy body size limits for large uploads","Retry aborted uploads instead of sending truncated parts"],"tags":["upload","multipart","validation"],"backgroundTag":"missing-upload-file","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}