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
- Raise the global limit in `payload.config.ts`: `upload: { limits: { fileSize: <larger bytes> } }` and redeploy.
- Compress/resize the file on the client before requesting upload instructions, and send the post-compression byte count as `filesize`.
- 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.
- 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
- Mirror the server's `config.upload.limits.fileSize` into a shared constant the client imports.
- Compute filesize from the real bytes you will upload, never from a larger source artifact.
- Compress media client-side before requesting upload instructions.
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
- Uploaded file is larger than expected.
- Operator handler "${handler.name}" cannot define both "build
- Operator handlers "${handlerA.name}" and "${handlerB.name}"
- Field ${field.label} has invalid relationship '${relationshi
- File type '${file.mimetype}' is not allowed.
AI-assisted analysis of payloadcms/payload@00c58b35c0 (2026-08-12).
Data as JSON: /api/errors/fe39beecd408cfd1.
Report an issue: GitHub.