{"record":{"id":"95c8334539af20f7","repo":"payloadcms/payload","slug":"file-type-mimetypefromextension-from-extension","errorCode":null,"errorMessage":"File type ${mimeTypeFromExtension} (from extension ${typeFromExtension}) is not allowed. / SVG file contains potentially harmful content. / Invalid or corrupted PDF file. / Invalid PDF file. / Invalid MIME type: ${detected.mime}. / File type '${file.mimetype}' not allowed ${file.name}: Restricted file type detected -- set 'allowRestrictedFileTypes' to true to skip this check for this Collection.","messagePattern":"File type (.+?) \\(from extension (.+?)\\) is not allowed\\. / SVG file contains potentially harmful content\\. / Invalid or corrupted PDF file\\. / Invalid PDF file\\. / Invalid MIME type: (.+?)\\. / File type '(.+?)' not allowed (.+?): Restricted file type detected -- set 'allowRestrictedFileTypes' to true to skip this check for this Collection\\.","errorType":"validation","errorClass":"ValidationError","httpStatus":400,"severity":"error","filePath":"packages/payload/src/uploads/checkFileRestrictions.ts","lineNumber":222,"sourceCode":"    if (detected && !passesMimeTypeCheck) {\n      errors.push(`Invalid MIME type: ${detected.mime}.`)\n    }\n  } else {\n    const isRestricted = RESTRICTED_FILE_EXT_AND_TYPES.some((type) => {\n      const hasRestrictedExt = type.extensions.some((ext) => file.name.toLowerCase().endsWith(ext))\n      const hasRestrictedMime = type.mimeType === file.mimetype\n      return hasRestrictedExt || hasRestrictedMime\n    })\n    if (isRestricted) {\n      errors.push(\n        `File type '${file.mimetype}' not allowed ${file.name}: Restricted file type detected -- set 'allowRestrictedFileTypes' to true to skip this check for this Collection.`,\n      )\n    }\n  }\n\n  if (errors.length > 0) {\n    req.payload.logger.error(errors.join(', '))\n    throw new ValidationError({\n      errors: [{ message: errors.join(', '), path: 'file' }],\n    })\n  }\n}\n","sourceCodeStart":204,"sourceCodeEnd":227,"githubUrl":"https://github.com/payloadcms/payload/blob/00c58b35c0ed348ddc22daabf467b139727214fd/packages/payload/src/uploads/checkFileRestrictions.ts#L204-L227","documentation":"Aggregate validation error thrown at the end of checkFileRestrictions when one or more content-level checks failed and were pushed into the errors[] array. Possible messages: (1) 'File type X (from extension Y) is not allowed.' — detected type was undefined and the extension's fallback MIME failed validateMimeType; (2) 'SVG file contains potentially harmful content.' — validateSvg flagged scripts/external refs; (3) 'Invalid or corrupted PDF file.' — extension-based PDF failed validatePDF; (4) 'Invalid PDF file.' — detected PDF failed validatePDF; (5) 'Invalid MIME type: <mime>.' — a type WAS detected but doesn't match upload.mimeTypes; (6) restricted-type message when no mimeTypes are configured and the file matches the blocklist. All collected errors are joined with ', ' in the final message.","triggerScenarios":"Uploading a file whose magic-byte-detected MIME disagrees with upload.mimeTypes (e.g. renamed .txt as .pdf); uploading an SVG containing <script> or external references; uploading a truncated/corrupt PDF; uploading an extension in the restricted list when mimeTypes is empty.","commonSituations":"Users renaming files to bypass extension filters; SVGs exported from design tools with inline scripts; PDFs truncated by interrupted uploads; allowing 'image/*' but receiving an SVG detected as application/xml without the SVG-XML detection branch firing; mimeTypes list missing the detected magic-byte type.","solutions":["Match the file's real content type: add the detected MIME to upload.mimeTypes, or have the user upload a non-spoofed file.","For SVGs, strip <script>, on* handlers, and external references before upload, or disable SVG uploads.","For PDFs, ensure the upload completed (re-upload a non-corrupt file); validate with a PDF tool client-side.","If you must accept a restricted/spoofed type, set upload.allowRestrictedFileTypes: true (skips checks) — understand the security implications first.","Read the full joined message to identify which of the six sub-checks fired before changing config."],"exampleFix":"// before — SVG with inline script rejected\nupload: { staticDir: 'media', mimeTypes: ['image/svg+xml'] }\n// after — sanitize SVGs upstream so validateSvg passes, or allow restricted types\nupload: {\n  staticDir: 'media',\n  mimeTypes: ['image/svg+xml'],\n  // only if you accept the risk:\n  // allowRestrictedFileTypes: true,\n}","handlingStrategy":"validation","validationCode":"import { validateSvg } from 'payload/uploads/validateSvg' // replicate logic if private\nimport { validatePDF } from 'payload/uploads/validatePDF'\nasync function preflightFile(buf: Buffer, ext: string): Promise<string[]> {\n  const errs: string[] = []\n  if (ext.toLowerCase() === 'svg' && !validateSvg(buf)) errs.push('SVG unsafe')\n  if (ext.toLowerCase() === 'pdf' && !validatePDF(buf)) errs.push('PDF corrupt')\n  return errs\n}","typeGuard":"const isSafeSvgName = (name: string): boolean =>\n  !/\\.svg$/i.test(name) || /^<\\?xml/.test('') /* placeholder; use validateSvg on bytes */","tryCatchPattern":"try {\n  await payload.create({ collection: 'media', file })\n} catch (e) {\n  if (e instanceof ValidationError) {\n    // e.data.errors[0].message holds the joined reasons\n    showUser(e.data.errors[0].message)\n  } else throw e\n}","preventionTips":["Sanitize SVGs (strip <script>, on*, external refs) before upload.","Validate PDFs client-side (e.g. pdf-lib) for large uploads.","Keep upload.mimeTypes explicit; avoid mixing wildcards with text types.","Log the joined error message to learn which sub-check fires in production."],"tags":["upload","validation","mime-type","svg","pdf","security"],"backgroundTag":null,"analyzedSha":"00c58b35c0ed348ddc22daabf467b139727214fd","analyzedAt":"2026-08-12T20:45:03.758Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}