payloadcms/payload · warning · APIError

Exceeded file size limit. Limit: ${bytesToMB(filesizeLimit).

Error message

Exceeded file size limit. Limit: ${bytesToMB(filesizeLimit).toFixed(2)}MB, got: ${bytesToMB(upload.filesize).toFixed(2)}MB

What it means

Payload enforces a single, global upload file-size ceiling configured at `config.upload.limits.fileSize` (bytes). When a client asks for upload instructions with a declared `filesize` that exceeds this global limit, the `getUploadInstructions` helper rejects the request with HTTP 400 *before* any bytes are staged. This is distinct from per-collection MIME/extension checks (handled later by `checkFileRestrictions`) and from adapter-specific limits.

Source

Thrown at packages/payload/src/uploads/endpoints/uploadInstructions.ts:50

export const getUploadInstructions = async ({
  overrideAccess = false,
  req,
  ...upload
}: {
  overrideAccess?: boolean
  req: PayloadRequest
} & UploadInstructionsRequest): Promise<UploadInstructions> => {
  const collection = req.payload.collections[upload.collectionSlug]
  const uploadInstructions = collection?.config?.upload?.uploadInstructions

  if (!collection?.config?.upload) {
    throw new APIError(`Upload collection ${upload.collectionSlug} was not found`, 400)
  }

  const filesizeLimit = req.payload.config.upload.limits?.fileSize
  if (filesizeLimit && upload.filesize > filesizeLimit) {
    throw new APIError(
      `Exceeded file size limit. Limit: ${bytesToMB(filesizeLimit).toFixed(2)}MB, got: ${bytesToMB(upload.filesize).toFixed(2)}MB`,
      400,
    )
  }

  await checkFileRestrictions({
    checkFileContents: false,
    collection: collection.config,
    file: {
      name: upload.filename,
      data: Buffer.alloc(0),
      mimetype: upload.mimeType,
      size: upload.filesize,
    },
    req,
  })

  if (!uploadInstructions && !overrideAccess) {

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Raise the global limit in `payload.config.ts`: `upload: { limits: { fileSize: <larger bytes> } }` and redeploy.
  2. Compress/resize the file on the client before requesting upload instructions, and send the post-compression byte count as `filesize`.
  3. Verify the client is sending the true final byte length (not a pre-transcode or padded size) and that the value is a non-negative safe integer.
  4. If the per-collection cap should differ, move the restriction to `upload.mimeTypes`/custom hooks instead of relying solely on the global limit.

Example fix

// before
export default buildConfig({
  upload: { limits: { fileSize: 10_000_000 } }, // 10 MB
})

// after
export default buildConfig({
  upload: { limits: { fileSize: 100_000_000 } }, // 100 MB
})
Defensive patterns

Strategy: validation

Validate before calling

import type { UploadInstructionsRequest } from 'payload'

const GLOBAL_FILE_SIZE_LIMIT = 50_000_000 // must match payload.config upload.limits.fileSize

function assertWithinGlobalLimit(req: UploadInstructionsRequest) {
  if (req.filesize > GLOBAL_FILE_SIZE_LIMIT) {
    throw new Error(
      `filesize ${req.filesize} exceeds global limit ${GLOBAL_FILE_SIZE_LIMIT}`,
    )
  }
}

// call before POST /upload-instructions
assertWithinGlobalLimit({ collectionSlug: 'media', filename, filesize, mimeType })

Type guard

function isUploadInstructionsRequest(u: unknown): u is UploadInstructionsRequest {
  return (
    !!u && typeof u === 'object' &&
    typeof (u as any).collectionSlug === 'string' &&
    typeof (u as any).filename === 'string' &&
    typeof (u as any).mimeType === 'string' &&
    typeof (u as any).filesize === 'number' &&
    Number.isSafeInteger((u as any).filesize) &&
    (u as any).filesize >= 0 &&
    (u as any).filesize <= GLOBAL_FILE_SIZE_LIMIT
  )
}

Try / catch

try {
  const res = await fetch(`${url}/api/upload-instructions`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) })
  if (res.status === 400) {
    const body = await res.json().catch(() => ({}))
    if (/file size limit/i.test(body.message ?? '')) {
      // filesize too large — compress/resize and retry, or raise config limit
    }
  }
} catch (err) {
  // network error
}

Prevention

When it happens

Trigger: Calling `POST /api/upload-instructions` (the `uploadInstructionsEndpoint`) — or the internal `getUploadInstructions({ collectionSlug, filename, filesize, mimeType, req })` — with a body whose `filesize` (a non-negative safe integer, validated by `isUploadInstructionsRequest`) is greater than `req.payload.config.upload.limits?.fileSize`. The global limit is read from the sanitized server config, not from the collection.

Common situations: A team sets a conservative `upload.limits.fileSize` (e.g. 10MB) and a user uploads a large video/PDF. The limit was lowered between releases and existing clients still send large files. The client reports the uncompressed size while intending to upload a compressed payload, so the declared `filesize` overshoots the cap even though the real bytes are smaller.

Related errors


AI-assisted analysis of payloadcms/payload@00c58b35c0 (2026-08-12). Data as JSON: /api/errors/fe39beecd408cfd1. Report an issue: GitHub.