Declared video mimetype not corrected to detected type (isProcessableImage only covers images)

Open Beginner friendly
#19,294 1 comment 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

@Emreceyhnn is already working on this.

Since Nov 3, 2026.

  • #19297 by @Emreceyhnn — open
  • #19298 by @suryakant-source — open

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
Domain
api, backend

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

Bug
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

Open in Codespaces

Starts the project's dev container in your browser, under your own GitHub account.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from payloadcms/payload

All issues in payloadcms/payload

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.