medusajs/medusa · error · MedusaError

No filename provided

Error message

No filename provided

What it means

upload requires file.filename to derive the storage path (path.parse(file.filename)); a file object without a filename is rejected with INVALID_DATA.

Source

Thrown at packages/modules/providers/file-local/src/services/local-file.ts:66

    // Since there is no way to serve private files through a static server, we simply place them in `static`.
    // This means that the files will be available publicly if the filename is known. Since the local file provider
    // is for development only, this shouldn't be an issue. If you really want to use it in production (and you shouldn't)
    // You can change the private upload dir to `/private` but none of the functionalities where you use a presigned URL will work.
    this.privateUploadDir_ =
      options?.private_upload_dir || path.join(process.cwd(), "static")
    this.backendUrl_ = options?.backend_url || "http://localhost:9000/static"
  }

  async upload(
    file: FileTypes.ProviderUploadFileDTO
  ): Promise<FileTypes.ProviderFileResultDTO> {
    if (!file) {
      throw new MedusaError(MedusaError.Types.INVALID_DATA, `No file provided`)
    }

    if (!file.filename) {
      throw new MedusaError(
        MedusaError.Types.INVALID_DATA,
        `No filename provided`
      )
    }

    const parsedFilename = path.parse(file.filename)
    const baseDir =
      file.access === "public" ? this.uploadDir_ : this.privateUploadDir_
    await this.ensureDirExists(baseDir, parsedFilename.dir)

    const fileKey = path.join(
      parsedFilename.dir,
      // We prepend "private" to the file key so deletions and presigned URLs can know which folder to look into
      `${file.access === "public" ? "" : "private-"}${Date.now()}-${
        parsedFilename.base
      }`
    )

View on GitHub (pinned to 5e06e544a2)

Solutions

  1. Ensure the file DTO includes a filename (with extension) before calling upload.
  2. On the client, append a real File/Blob with a filename: formData.append('files', file, 'photo.png').
  3. If generating a name server-side, set it explicitly on the DTO before upload.

Example fix

// before
await fileService.upload({ url: "", content: buffer })
// after
await fileService.upload({ filename: `uploads/${Date.now()}.png`, mimeType: "image/png", content: buffer })
Defensive patterns

Strategy: type-guard

Validate before calling

if (!file?.filename) {
  return res.status(400).json({ message: "No filename provided" })
}

Type guard

const hasFilename = (f: FileTypes.ProviderUploadFileDTO | undefined): f is FileTypes.ProviderUploadFileDTO & { filename: string } =>
  typeof f?.filename === "string" && f.filename.length > 0

Try / catch

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 }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of medusajs/medusa@5e06e544a2 (2026-08-27). Data as JSON: /api/errors/80773edaaf2d4bfe. Report an issue: GitHub.