payloadcms/payload · error · APIError

Uploaded file size does not match the expected size.

Error message

Uploaded file size does not match the expected size.

What it means

Thrown after the PUT body stream for a staged upload finishes: the total bytes received do not equal the `filesize` declared when the staged upload instructions were generated. Payload uses the declared size to pre-validate and atomically rename the temp file, so a mismatch means the upload cannot be finalized.

Source

Thrown at packages/payload/src/uploads/stagedUpload.ts:103

        if (done) {
          break
        }

        uploadedSize += value.byteLength
        if (uploadedSize > upload.filesize) {
          throw new APIError('Uploaded file is larger than expected.', 400)
        }

        let offset = 0
        while (offset < value.byteLength) {
          const { bytesWritten } = await file.write(value, offset)
          offset += bytesWritten
        }
      }

      if (uploadedSize !== upload.filesize) {
        throw new APIError('Uploaded file size does not match the expected size.', 400)
      }
    } finally {
      await file.close()
    }

    const collection = req.payload.collections[upload.collectionSlug]!.config
    await checkFileRestrictions({
      collection,
      file: {
        name: upload.filename,
        data: Buffer.alloc(0),
        mimetype: upload.mimeType,
        size: upload.filesize,
        tempFilePath: temporaryPath,
      },
      req,
    })

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Verify the `filesize` value passed to `generateStagedUploadInstructions` matches the actual byte length of the blob you PUT.
  2. Ensure the HTTP client sends the entire body without early abort -- check for network interruptions or client-side timeouts.
  3. Confirm no intermediary (nginx client_max_body_size, CDN, or compression) alters the body length.
  4. If resuming, request fresh upload instructions for the correct file size rather than reusing an old uploadId.

Example fix

// before
const instructions = await generateStagedUploadInstructions({
  filesize: file.size, // stale or wrong value
  ...
})
await fetch(instructions.request.url, { method: 'PUT', body: partialBlob })

// after
const buf = await file.arrayBuffer()
const instructions = await generateStagedUploadInstructions({
  filesize: buf.byteLength, // exact byte count
  ...
})
await fetch(instructions.request.url, { method: 'PUT', body: buf })
Defensive patterns

Strategy: validation

Validate before calling

// Before PUT, confirm the blob byte length matches the declared size
const buf = await file.arrayBuffer()
if (buf.byteLength !== declaredFilesize) {
  throw new Error(`Size mismatch: blob is ${buf.byteLength}, expected ${declaredFilesize}`)
}
await fetch(uploadUrl, { method: 'PUT', body: buf, headers: { 'Content-Length': String(buf.byteLength) } })

Try / catch

// Wrap the PUT; on failure, re-stage instead of retrying with stale uploadId
try {
  await putStagedBytes(uploadId, buffer)
} catch (e) {
  if (e instanceof APIError && e.message.includes('does not match')) {
    const fresh = await generateStagedUploadInstructions({ filesize: buffer.byteLength, ... })
    await putStagedBytes(fresh.uploadId, buffer)
  } else throw e
}

Prevention

When it happens

Trigger: A client sends a PUT to the `/upload-instructions/:uploadId` URL with a body whose total byte count is less than (or, having passed the larger-than check, somehow not equal to) the `filesize` encoded in the signed uploadId JWT. Typical causes: the client aborted early, a proxy truncated the body, or `Content-Length` / stream length disagrees with the value passed to `generateStagedUploadInstructions`.

Common situations: Client-side progress upload that stops sending chunks before completion; a reverse proxy or CDN that buffers or strips part of the body; the `filesize` passed at instruction-generation time was computed incorrectly (e.g. using a `File` object whose size changed, or a stat read before the file finished writing).

Related errors


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