{"record":{"id":"c14c721260ca8867","repo":"medusajs/medusa","slug":"file-with-key-file-filekey-not-found","errorCode":null,"errorMessage":"File with key ${file.fileKey} not found","messagePattern":"File with key (.+?) not found","errorType":"exception","errorClass":"MedusaError","httpStatus":404,"severity":"error","filePath":"packages/modules/providers/file-local/src/services/local-file.ts","lineNumber":210,"sourceCode":"      : this.uploadDir_\n\n    const filePath = this.getUploadFilePath(baseDir, file.fileKey)\n    return fs.readFile(filePath)\n  }\n\n  // The local file provider doesn't support presigned URLs for private files (i.e files not placed in /static).\n  async getPresignedDownloadUrl(\n    file: FileTypes.ProviderGetFileDTO\n  ): Promise<string> {\n    const isPrivate = file.fileKey.startsWith(\"private-\")\n    const baseDir = isPrivate ? this.privateUploadDir_ : this.uploadDir_\n\n    const filePath = this.getUploadFilePath(baseDir, file.fileKey)\n\n    try {\n      await fs.access(filePath, fs.constants.F_OK)\n    } catch {\n      throw new MedusaError(\n        MedusaError.Types.NOT_FOUND,\n        `File with key ${file.fileKey} not found`\n      )\n    }\n\n    return this.getUploadFileUrl(file.fileKey)\n  }\n\n  /**\n   * Returns the pre-signed URL that the client (frontend) can use to trigger\n   * a file upload. In this case, the Medusa backend will implement the\n   * \"/upload\" endpoint to perform the file upload.\n   */\n  async getPresignedUploadUrl(\n    fileData: FileTypes.ProviderGetPresignedUploadUrlDTO\n  ): Promise<FileTypes.ProviderFileResultDTO> {\n    if (!fileData?.filename) {\n      throw new MedusaError(","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/medusajs/medusa/blob/5e06e544a296b9033f20f71f11c559f81a0e5739/packages/modules/providers/file-local/src/services/local-file.ts#L192-L228","documentation":"Before minting a (local) presigned download URL, the service checks the file exists on disk with fs.access(F_OK); if not found it throws NOT_FOUND naming the fileKey, because serving a URL for a nonexistent local file would just 404 later.","triggerScenarios":"Calling getFileDownloadUrl/getPresignedDownloadUrl with a fileKey that was never uploaded, was deleted from the local storage directory, or points outside the provider's base directory naming scheme (e.g. missing the prefix folder).","commonSituations":"DB rows referencing files uploaded under a different upload_dir or a previous container (local storage is ephemeral in docker — files vanish on redeploy); fileKey typo or missing prefix; the file was soft-deleted but the record retained; switching file providers (S3→local) without migrating objects.","solutions":["Verify the fileKey matches what upload returned and that the file exists under the configured local upload directory.","If running local-file in a container, mount a persistent volume for the upload dir so files survive restarts.","Delete stale DB references or re-upload the missing assets."],"exampleFix":"// before\nconst { url } = await fileService.getPresignedDownloadUrl({ fileKey: row.file_key })\n// after\nconst { url } = await fileService.getPresignedDownloadUrl({ fileKey: row.file_key, isPrivate: row.private }).catch((e) => {\n  if (e.type === MedusaError.Types.NOT_FOUND) return null // treat as missing asset\n  throw e\n})","handlingStrategy":"fallback","validationCode":"import fs from \"fs/promises\"\nasync function fileExists(path: string): Promise<boolean> {\n  try { await fs.access(path); return true } catch { return false }\n}","typeGuard":"const isMissingFileError = (e: unknown): boolean =>\n  e instanceof MedusaError && e.type === MedusaError.Types.NOT_FOUND && /not found/.test(e.message)","tryCatchPattern":"try {\n  const { url } = await fileService.getPresignedDownloadUrl({ fileKey })\n} catch (e) {\n  if (isMissingFileError(e)) {\n    // fallback: placeholder asset or 404 page\n    return res.status(404).json({ message: \"File no longer available\" })\n  }\n  throw e\n}","preventionTips":["Mount a persistent volume for the local upload dir in containers.","Clean up DB records when deleting local files.","Re-upload or migrate assets when switching file providers."],"tags":["file-storage","not-found","download-url","local-provider"],"backgroundTag":"file-not-found","analyzedSha":"5e06e544a296b9033f20f71f11c559f81a0e5739","analyzedAt":"2026-08-27T07:24:39.599Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}