{"record":{"id":"80773edaaf2d4bfe","repo":"medusajs/medusa","slug":"no-filename-provided","errorCode":null,"errorMessage":"No filename provided","messagePattern":"No filename provided","errorType":"exception","errorClass":"MedusaError","httpStatus":400,"severity":"error","filePath":"packages/modules/providers/file-local/src/services/local-file.ts","lineNumber":66,"sourceCode":"\n    // Since there is no way to serve private files through a static server, we simply place them in `static`.\n    // This means that the files will be available publicly if the filename is known. Since the local file provider\n    // is for development only, this shouldn't be an issue. If you really want to use it in production (and you shouldn't)\n    // You can change the private upload dir to `/private` but none of the functionalities where you use a presigned URL will work.\n    this.privateUploadDir_ =\n      options?.private_upload_dir || path.join(process.cwd(), \"static\")\n    this.backendUrl_ = options?.backend_url || \"http://localhost:9000/static\"\n  }\n\n  async upload(\n    file: FileTypes.ProviderUploadFileDTO\n  ): Promise<FileTypes.ProviderFileResultDTO> {\n    if (!file) {\n      throw new MedusaError(MedusaError.Types.INVALID_DATA, `No file provided`)\n    }\n\n    if (!file.filename) {\n      throw new MedusaError(\n        MedusaError.Types.INVALID_DATA,\n        `No filename provided`\n      )\n    }\n\n    const parsedFilename = path.parse(file.filename)\n    const baseDir =\n      file.access === \"public\" ? this.uploadDir_ : this.privateUploadDir_\n    await this.ensureDirExists(baseDir, parsedFilename.dir)\n\n    const fileKey = path.join(\n      parsedFilename.dir,\n      // We prepend \"private\" to the file key so deletions and presigned URLs can know which folder to look into\n      `${file.access === \"public\" ? \"\" : \"private-\"}${Date.now()}-${\n        parsedFilename.base\n      }`\n    )\n","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/medusajs/medusa/blob/5e06e544a296b9033f20f71f11c559f81a0e5739/packages/modules/providers/file-local/src/services/local-file.ts#L48-L84","documentation":"upload requires file.filename to derive the storage path (path.parse(file.filename)); a file object without a filename is rejected with INVALID_DATA.","triggerScenarios":"Calling upload({ stream/content }) with no filename key, or filename: \"\" — e.g. a form part without a filename or a programmatic upload that only passes a buffer.","commonSituations":"Multipart parsing configured to keep fields only; client using fetch/axios with the wrong form field setup so the filename metadata is lost; tests constructing FileTypes.ProviderUploadFileDTO partially.","solutions":["Ensure the file DTO includes a filename (with extension) before calling upload.","On the client, append a real File/Blob with a filename: formData.append('files', file, 'photo.png').","If generating a name server-side, set it explicitly on the DTO before upload."],"exampleFix":"// before\nawait fileService.upload({ url: \"\", content: buffer })\n// after\nawait fileService.upload({ filename: `uploads/${Date.now()}.png`, mimeType: \"image/png\", content: buffer })","handlingStrategy":"type-guard","validationCode":"if (!file?.filename) {\n  return res.status(400).json({ message: \"No filename provided\" })\n}","typeGuard":"const hasFilename = (f: FileTypes.ProviderUploadFileDTO | undefined): f is FileTypes.ProviderUploadFileDTO & { filename: string } =>\n  typeof f?.filename === \"string\" && f.filename.length > 0","tryCatchPattern":"try { await fileService.upload(file) } catch (e) { if (e instanceof MedusaError && /No filename provided/.test(e.message)) { res.status(400).json({ message: e.message }); return } throw e }","preventionTips":["Append File/Blob parts with an explicit filename on the client.","Derive or generate a filename server-side when clients may omit it.","Validate DTO shape in tests with a helper."],"tags":["file-upload","filename","validation","local-provider"],"backgroundTag":"missing-filename","analyzedSha":"5e06e544a296b9033f20f71f11c559f81a0e5739","analyzedAt":"2026-08-27T07:24:39.599Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}