payloadcms/payload · error · APIError

Invalid upload instructions request

Error message

Invalid upload instructions request

What it means

The endpoint runs `isUploadInstructionsRequest`, a runtime type guard that verifies the parsed JSON has the exact shape Payload needs: `collectionSlug: string`, `filename: string`, `filesize: number` that is a **safe integer ≥ 0**, `mimeType: string`, and (if present) `docPrefix: string`. Any deviation throws HTTP 400. Notably `filesize` must be a non-negative safe integer — a float, negative, or value beyond `Number.MAX_SAFE_INTEGER` fails.

Source

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

    if (!collectionPermissions?.create && !collectionPermissions?.update) {
      throw new Forbidden(req.t)
    }
  }

  return uploadInstructions
    ? uploadInstructions.generate({ ...upload, overrideAccess, req })
    : generateStagedUploadInstructions({ ...upload, req })
}

export const uploadInstructionsEndpoint: Endpoint = {
  handler: async (req) => {
    if (!req.json) {
      throw new APIError('Content-Type expected to be application/json', 400)
    }

    const upload: unknown = await req.json()
    if (!isUploadInstructionsRequest(upload)) {
      throw new APIError('Invalid upload instructions request', 400)
    }

    return Response.json(await getUploadInstructions({ ...upload, req }))
  },
  method: 'post',
  path: '/upload-instructions',
}

/**
 * Stores or removes temporary files when no adapter-specific upload instructions are available.
 * PUT keeps the file until it is used in a document request.
 * DELETE removes a file the client no longer needs.
 */
export const stagedUploadEndpoints: Endpoint[] = [
  {
    handler: uploadStagedFile,
    method: 'put',
    path: '/upload-instructions/:uploadId',

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Validate the payload against `UploadInstructionsRequest` (collectionSlug/filename/mimeType strings, filesize a non-negative safe integer) before sending.
  2. Coerce `filesize` to `Math.max(0, Math.trunc(Number(filesize)))` and guard `Number.isSafeInteger`.
  3. Sync client types with the server's `UploadInstructionsRequest` interface from `payload`.
  4. Ensure the body is a flat object, not nested under a wrapper key.

Example fix

// before
fetch(`${url}/api/upload-instructions`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    collection: 'media',          // wrong key (should be collectionSlug)
    filename: 'a.png',
    filesize: '2048',             // string, not number
    mimeType: 'image/png',
  }),
})

// after
const payload = {
  collectionSlug: 'media',
  filename: 'a.png',
  filesize: 2048,                 // number, safe integer >= 0
  mimeType: 'image/png',
}
fetch(`${url}/api/upload-instructions`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(payload),
})
Defensive patterns

Strategy: type-guard

Validate before calling

function isUploadInstructionsRequest(u: unknown): u is UploadInstructionsRequest {
  if (!u || typeof u !== 'object') return false
  const o = u as Record<string, unknown>
  return (
    typeof o.collectionSlug === 'string' &&
    typeof o.filename === 'string' &&
    typeof o.mimeType === 'string' &&
    typeof o.filesize === 'number' &&
    Number.isSafeInteger(o.filesize) &&
    o.filesize >= 0 &&
    (o.docPrefix === undefined || typeof o.docPrefix === 'string')
  )
}

const body = { collectionSlug: 'media', filename, filesize: Math.trunc(file.size), mimeType }
if (!isUploadInstructionsRequest(body)) {
  throw new Error('Invalid upload-instructions payload')
}

Type guard

const isUploadInstructionsRequest = (u: unknown): u is UploadInstructionsRequest =>
  !!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

Try / catch

try {
  if (!isUploadInstructionsRequest(payload)) throw new Error('bad shape')
  await fetch(`${url}/api/upload-instructions`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) })
} catch (err) {
  if (/invalid upload instructions request/i.test(String(err))) {
    // fix field types and retry
  }
}

Prevention

When it happens

Trigger: `POST /api/upload-instructions` whose JSON body is missing a required field, has a wrong-typed field (e.g. `filesize: "12345"` as a string), contains a negative or fractional `filesize`, or `docPrefix` is a non-string type. Also thrown if the body parses to a non-object or null.

Common situations: Client sends `filesize` as a string from a form field. `docPrefix` is accidentally an object. A field is omitted because the client schema is out of sync with the server version. The body is `null` or an array. `filesize` is `NaN` from a failed `parseInt`.

Related errors


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