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
- 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.
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
- 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.
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
- No file provided
- --paths must be a directory - ${additionalPath}
- --base must be a file - ${baseFile}
- insufficient_inventory
- not_found
AI-assisted analysis of medusajs/medusa@5e06e544a2 (2026-08-27).
Data as JSON: /api/errors/80773edaaf2d4bfe.
Report an issue: GitHub.