{"record":{"id":"0b2d1a0c997226b9","repo":"medusajs/medusa","slug":"no-file-provided","errorCode":null,"errorMessage":"No file provided","messagePattern":"No file provided","errorType":"exception","errorClass":"MedusaError","httpStatus":400,"severity":"error","filePath":"packages/modules/providers/file-local/src/services/local-file.ts","lineNumber":62,"sourceCode":"\n  constructor(_, options: LocalFileServiceOptions) {\n    super()\n    this.uploadDir_ = options?.upload_dir || path.join(process.cwd(), \"static\")\n\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()}-${","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/medusajs/medusa/blob/5e06e544a296b9033f20f71f11c559f81a0e5739/packages/modules/providers/file-local/src/services/local-file.ts#L44-L80","documentation":"The local file service's upload rejects a falsy file argument with INVALID_DATA before doing anything else — there is no file object to read a filename or stream from.","triggerScenarios":"Calling provider.upload(undefined/null), typically because an upstream form-parse failed or an empty multipart body was submitted.","commonSituations":"An upload API route forwarding req.body when the client sent no file; tests calling the service directly with no argument; a refactor that renamed the variable holding the parsed file.","solutions":["Check the multipart/form-data parse result before delegating: if no file part exists, return a 400 instead of calling upload.","On the client, ensure the file field name matches what the server/middleware expects and that Content-Type is multipart/form-data.","In route code, validate file presence before invoking the file service."],"exampleFix":"// before\nconst result = await fileService.upload(req.body.file) // undefined when no file part\n// after\nif (!req.file) return res.status(400).json({ message: \"No file provided\" })\nconst result = await fileService.upload(req.file)","handlingStrategy":"validation","validationCode":"if (!file) {\n  return res.status(400).json({ message: \"No file provided\" })\n}\nawait fileService.upload(file)","typeGuard":"const isUploadFileDTO = (f: unknown): f is FileTypes.ProviderUploadFileDTO =>\n  !!f && typeof f === \"object\" && typeof (f as any).filename === \"string\"","tryCatchPattern":"try { await fileService.upload(file) } catch (e) { if (e instanceof MedusaError && /No file provided/.test(e.message)) { res.status(400).json({ message: e.message }); return } throw e }","preventionTips":["Validate the multipart parse result before delegating to the file service.","Set client-side required-field checks on file inputs.","Return early 400s for empty bodies rather than letting the service throw."],"tags":["file-upload","validation","local-provider"],"backgroundTag":"empty-upload-body","analyzedSha":"5e06e544a296b9033f20f71f11c559f81a0e5739","analyzedAt":"2026-08-27T07:24:39.599Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}