{"record":{"id":"769fdeaacd20ad14","repo":"payloadcms/payload","slug":"file-type-file-mimetype-is-not-allowed","errorCode":null,"errorMessage":"File type '${file.mimetype}' is not allowed.","messagePattern":"File type '(.+?)' is not allowed\\.","errorType":"validation","errorClass":"ValidationError","httpStatus":400,"severity":"error","filePath":"packages/payload/src/uploads/checkFileRestrictions.ts","lineNumber":101,"sourceCode":"    )\n  }\n\n  // Skip validation if `allowRestrictedFileTypes` is true\n  if (allowRestrictedFileTypes) {\n    return\n  }\n\n  if (!checkFileContents) {\n    const isAllowed = configMimeTypes.length\n      ? validateMimeType(file.mimetype, configMimeTypes)\n      : !RESTRICTED_FILE_EXT_AND_TYPES.some(\n          ({ extensions, mimeType }) =>\n            mimeType === file.mimetype ||\n            extensions.some((extension) => file.name.toLowerCase().endsWith(extension)),\n        )\n\n    if (!isAllowed) {\n      throw new ValidationError({\n        errors: [{ message: `File type '${file.mimetype}' is not allowed.`, path: 'file' }],\n      })\n    }\n\n    return\n  }\n\n  // For temp files, use fileTypeFromFile so large files (e.g. video) are never loaded into memory\n  // just for detection. For content validation (SVG safety, PDF integrity), the full buffer is\n  // loaded lazily and only when the file type actually requires it.\n  const { tempFilePath } = file\n  const isTempFile = !!tempFilePath && (!file.data || file.data.length === 0)\n\n  // Lazily reads the full file — only reached for small text-based types (SVG, PDF).\n  let _fileBuffer: Buffer | undefined\n  const getFileBuffer = async (): Promise<Buffer> => {\n    if (_fileBuffer) {\n      return _fileBuffer","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/payloadcms/payload/blob/00c58b35c0ed348ddc22daabf467b139727214fd/packages/payload/src/uploads/checkFileRestrictions.ts#L83-L119","documentation":"Thrown by checkFileRestrictions on the fast-path that skips buffer inspection (checkFileContents === false), used by the upload-instructions endpoint and pre-flight checks. The uploaded file's mimetype fails validation: if the collection defines upload.mimeTypes, the file's mimetype must match one of them (via validateMimeType prefix matching, where '*' is stripped); otherwise the file is rejected when its mimetype OR filename extension matches the RESTRICTED_FILE_EXT_AND_TYPES blocklist (executables, scripts, HTML, etc.).","triggerScenarios":"POST /api/:collection/upload-instructions or a local upload where (a) upload.mimeTypes is set and file.mimetype does not start with any configured entry (note '*' is stripped, so 'image/*' matches any 'image/...'), or (b) upload.mimeTypes is unset and the file extension/mimetype is in the built-in restricted list (e.g. .exe, .html, .php, .js, .bat).","commonSituations":"Forgetting to add 'application/pdf' or a specific image type to upload.mimeTypes; uploading an SVG with mimetype 'image/svg+xml' while only listing generic types; client sending a generic 'application/octet-stream' that isn't in the allow list; trying to upload HTML/JS that the blocklist catches even when no mimeTypes are configured.","solutions":["Add the file's mimetype (or a wildcard like 'image/*') to the collection's upload.mimeTypes array in the config.","Rename the file so its extension is not in RESTRICTED_FILE_EXT_AND_TYPES, or confirm the client sends the correct Content-Type.","If you intentionally accept restricted types, set upload.allowRestrictedFileTypes: true on the collection (disables the blocklist check entirely).","Verify the client is sending the real mimetype (FormData/Blob type) rather than a default 'application/octet-stream'."],"exampleFix":"// before\nupload: { staticDir: 'media', mimeTypes: ['application/pdf'] }\n// after — allow all images plus PDFs and SVGs\nupload: { staticDir: 'media', mimeTypes: ['image/*', 'application/pdf', 'image/svg+xml'] }","handlingStrategy":"validation","validationCode":"import { validateMimeType } from 'payload/utilities' // or replicate the prefix logic\nconst ALLOWED = ['image/*', 'application/pdf', 'image/svg+xml'] // mirror upload.mimeTypes\nfunction isAllowedRequest(mimetype: string, filename: string): boolean {\n  const cleaned = ALLOWED.map((m) => m.replace('*', ''))\n  const matchesConfig = cleaned.some((c) => mimetype.startsWith(c))\n  return matchesConfig\n}\n// call before upload:\nif (!isAllowedRequest(file.type, file.name)) throw new Error('Pick a file of an allowed type')","typeGuard":"const isAcceptableMime = (m: string): boolean =>\n  ['image/', 'video/', 'audio/', 'application/pdf', 'image/svg+xml'].some((p) =>\n    m.startsWith(p.replace('*', '')),\n  )","tryCatchPattern":"try {\n  await payload.create({ collection: 'media', data, file })\n} catch (e) {\n  if (e instanceof APIError && /File type .* is not allowed/.test(e.message)) {\n    notifyUser('That file type is not allowed. Allowed: ' + ALLOWED.join(', '))\n  } else throw e\n}","preventionTips":["Keep the client's accepted attribute in sync with upload.mimeTypes (e.g. <input accept='image/*,application/pdf'>).","Document the configured mimeTypes in your API docs so consumers know the contract.","Use wildcard entries ('image/*') carefully — they broaden acceptance.","Run a pre-flight check against the upload-instructions endpoint to fail fast."],"tags":["upload","validation","mime-type","config"],"backgroundTag":null,"analyzedSha":"00c58b35c0ed348ddc22daabf467b139727214fd","analyzedAt":"2026-08-12T20:45:03.758Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}