payloadcms/payload · error · ValidationError
File type ${mimeTypeFromExtension} (from extension ${typeFro
Error message
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. What it means
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.
Source
Thrown at packages/payload/src/uploads/checkFileRestrictions.ts:222
if (detected && !passesMimeTypeCheck) {
errors.push(`Invalid MIME type: ${detected.mime}.`)
}
} else {
const isRestricted = RESTRICTED_FILE_EXT_AND_TYPES.some((type) => {
const hasRestrictedExt = type.extensions.some((ext) => file.name.toLowerCase().endsWith(ext))
const hasRestrictedMime = type.mimeType === file.mimetype
return hasRestrictedExt || hasRestrictedMime
})
if (isRestricted) {
errors.push(
`File type '${file.mimetype}' not allowed ${file.name}: Restricted file type detected -- set 'allowRestrictedFileTypes' to true to skip this check for this Collection.`,
)
}
}
if (errors.length > 0) {
req.payload.logger.error(errors.join(', '))
throw new ValidationError({
errors: [{ message: errors.join(', '), path: 'file' }],
})
}
}
View on GitHub (pinned to 00c58b35c0)
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.
Example fix
// before — SVG with inline script rejected
upload: { staticDir: 'media', mimeTypes: ['image/svg+xml'] }
// after — sanitize SVGs upstream so validateSvg passes, or allow restricted types
upload: {
staticDir: 'media',
mimeTypes: ['image/svg+xml'],
// only if you accept the risk:
// allowRestrictedFileTypes: true,
} Defensive patterns
Strategy: validation
Validate before calling
import { validateSvg } from 'payload/uploads/validateSvg' // replicate logic if private
import { validatePDF } from 'payload/uploads/validatePDF'
async function preflightFile(buf: Buffer, ext: string): Promise<string[]> {
const errs: string[] = []
if (ext.toLowerCase() === 'svg' && !validateSvg(buf)) errs.push('SVG unsafe')
if (ext.toLowerCase() === 'pdf' && !validatePDF(buf)) errs.push('PDF corrupt')
return errs
} Type guard
const isSafeSvgName = (name: string): boolean =>
!/\.svg$/i.test(name) || /^<\?xml/.test('') /* placeholder; use validateSvg on bytes */ Try / catch
try {
await payload.create({ collection: 'media', file })
} catch (e) {
if (e instanceof ValidationError) {
// e.data.errors[0].message holds the joined reasons
showUser(e.data.errors[0].message)
} else throw e
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- File type '${file.mimetype}' is not allowed.
- The provided URL is not allowed.
- ${value} is not allowed as a JSON query value
- Invalid path segment. Only alphanumeric characters and under
- Field ${field.label} has invalid relationship '${relationshi
AI-assisted analysis of payloadcms/payload@00c58b35c0 (2026-08-12).
Data as JSON: /api/errors/95c8334539af20f7.
Report an issue: GitHub.