Declared video mimetype not corrected to detected type (isProcessableImage only covers images)
Maintainers usually reply within 1 day
@Emreceyhnn is already working on this.
Since Nov 3, 2026.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 72/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- nodejs, typescript
Research direction
Start in packages/payload/src/uploads/generateFileData.ts and trace how the detected MIME type is used alongside checkFileRestrictions for upload allow-lists. Update the correction behavior so accepted files store the sniffed type, then add or adjust a regression test for the video/webm bytes declared as video/mp4 case. Done when the stored MIME type matches the detected type for the described video upload.
Written by the indexing model from the issue text.
Description
Link to reproduction
No public repro repo; reproduced locally via Local API, steps below.
Describe the Bug
generateFileData's correction of a wrong declared file.mimetype to the real, sniffed type only fires when isProcessableImage(file.mimetype) || isProcessableImage(detectedFileType.mime) is true:
// packages/payload/src/uploads/generateFileData.ts
const shouldUseDetectedFileType =
detectedFileType &&
(isProcessableImage(file.mimetype) || isProcessableImage(detectedFileType.mime))
if (shouldUseDetectedFileType && detectedFileType.mime !== file.mimetype) {
file = { ...file, mimetype: detectedFileType.mime }
}
isProcessableImage (isImage(mimeType) || canResizeImage(mimeType)) is image-only. For two video mimetypes that are both in an upload collection's mimeTypes allow-list, this condition is always false, so a file is accepted (checkFileRestrictions validates the real, sniffed type against the allow-list) but the stored mimeType keeps whatever was declared, even when it doesn't match the real file bytes.
This only affects paths where the caller doesn't already pass the correct, pre-sniffed mimetype itself (REST/GraphQL multipart uploads, Admin Panel, any custom Local API caller that passes its own file.mimetype). It does not affect the collection's content-type acceptance -- only the mimetype value Payload stores.
To Reproduce
Collection:
export const Media: CollectionConfig = {
slug: 'media',
upload: {
mimeTypes: ['video/mp4', 'video/webm'],
},
fields: [],
}
Local API, with a real webm file's bytes but a wrong declared video/mp4:
const result = await payload.create({
collection: 'media',
data: {},
file: {
data: realWebmBuffer, // actual webm bytes
mimetype: 'video/mp4', // wrong on purpose
name: 'clip.mp4',
size: realWebmBuffer.length,
},
})
console.log(result.mimeType) // "video/mp4" -- wrong; file is really video/webm
The create succeeds (no ValidationError, since the real, sniffed type video/webm is itself in the allow-list), but result.mimeType is video/mp4, not the real video/webm.
The same repro with the mimetypes swapped (real mp4 bytes, declared video/webm) stores video/webm instead of the real video/mp4.
For comparison, the equivalent image case is already handled correctly: a file with real PNG bytes but a declared image/jpeg gets corrected to image/png in the stored document, because isProcessableImage covers images.
Expected behavior
The sniffed-vs-declared mimetype correction in generateFileData should apply uniformly to any mimetype in the collection's own upload.mimeTypes allow-list (or at minimum to any type checkFileRestrictions already validated against the real bytes), not just image types gated by isProcessableImage.
Payload Version
3.90.2
Adapters and Plugins
None relevant -- reproduces with the default local-disk upload adapter.
- Dominant language
- TypeScript
- Stars
- 45.6k
- Forks
- 4.4k
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 261
Getting set up
Starts the project's dev container in your browser, under your own GitHub account.
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from payloadcms/payload
-
sdk: `fallbackLocale: false` is not sent to the REST APIPossibly taken A pull request linked to this issue is open or already merged. OpenBug invalid-reproduction status: needs-triage v3
Difficulty 2/5 1-3 hours Newbie friendliness 83/100
payloadcms/payload#19387 · 2 comments ·
Maintainers usually reply within 1 day
-
richtext-lexical: the editor upload card shows the cropped `thumbnail` size instead of the imageOpenBug
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
payloadcms/payload#19318 · 1 comment ·
Maintainers usually reply within 1 day
-
richtext-lexical: `slashMenu.dynamicGroups` are dropped (self-concatenation in the merge, and not offered on a bare "/")Possibly taken @muhammad-wasif-code claimed this 2 days ago. OpenBug
Difficulty 2/5 1-3 hours Newbie friendliness 77/100
payloadcms/payload#19317 · 1 comment ·
Maintainers usually reply within 1 day
-
ui field: admin.components.Cell is rendered in the edit view's form state and throws (`key in` on an array in renderField)Possibly taken A pull request linked to this issue is open or already merged. Openarea: ui Bug status: needs-triage v3
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
payloadcms/payload#19314 ·
Maintainers usually reply within 1 day
-
File URLs get a trailing slash when Next.js trailingSlash is enabled (404 on every upload)Possibly taken A pull request linked to this issue is open or already merged. Openarea: core area: uploads Bug
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
payloadcms/payload#19292 ·
Maintainers usually reply within 1 day
All issues in payloadcms/payload
Similar issues
-
The sample email preview's ResizeObserver is never disconnected and keeps raising errors after leaving SettingsPossibly taken A pull request linked to this issue is open or already merged. Openbug
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
Maintainers usually reply within 1 day
-
area:ui bug effort:S priority:P2
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 1 day
-
Typo in WSL project description on Projects pagePossibly taken @akhil9tiet claimed this today. Open
Difficulty 1/5 Under an hour Newbie friendliness 75/100
microsoft/opensource.microsoft.com#1066 · 1 comment ·
-
ArcGIS Maps SDK for JavaScript c-carousel calcite-design-tokens enhancement impact - p3 - not time sensitive needs triage
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
Esri/calcite-design-system#15565 ·
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
linkwarden/linkwarden#1891 ·
Maintainers usually reply within 1 day