{"record":{"id":"c7c5f9e288586c5d","repo":"Budibase/budibase","slug":"attempted-to-upload-a-file-without-a-filename","errorCode":null,"errorMessage":"Attempted to upload a file without a filename","messagePattern":"Attempted to upload a file without a filename","errorType":"http","errorClass":"BadRequestError","httpStatus":400,"severity":"error","filePath":"packages/server/src/api/controllers/static/index.ts","lineNumber":264,"sourceCode":"}\n\nexport const uploadFile = async function (\n  ctx: Ctx<void, ProcessAttachmentResponse>\n) {\n  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","sourceCodeStart":246,"sourceCodeEnd":282,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/api/controllers/static/index.ts#L246-L282","documentation":"Thrown by uploadFile when an uploaded part has no resolvable filename (getUploadFilename returns falsy). Every stored file needs a name to compute its key/extension.","triggerScenarios":"Uploading a file part with an empty filename, a Blob created without a filename in FormData, or a client sending a part without a filename attribute in Content-Disposition.","commonSituations":"JavaScript clients appending a raw Blob (no third argument), curl -F without @filename, or programmatic multipart construction omitting the filename.","solutions":["Provide a filename when appending: fd.append('file', blob, 'photo.png')","Use curl's @path syntax so a filename is included","Fix server-side multipart parsing if it strips filenames"],"exampleFix":"// before\nfd.append('file', new Blob([data]))\n// after\nfd.append('file', new Blob([data]), 'report.pdf')","handlingStrategy":"validation","validationCode":"function uploadHasFilename(file) {\n  return Boolean(file && file.name && file.name.length > 0)\n}","typeGuard":"const hasFilename = (f: unknown): f is { name: string } =>\n  typeof f === 'object' && f !== null && typeof (f as any).name === 'string' && (f as any).name.length > 0","tryCatchPattern":"try {\n  await api.uploadFile(fd)\n} catch (err) {\n  if (err instanceof BadRequestError && err.message.includes('without a filename')) {\n    // re-append the blob with an explicit filename\n  } else throw err\n}","preventionTips":["Always pass a filename as the third FormData.append argument for Blobs","Use File objects (which carry a name) rather than raw Blobs","Check Content-Disposition includes filename= in the outgoing request"],"tags":["upload","multipart","validation"],"backgroundTag":"missing-upload-filename","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}