{"record":{"id":"b8061217bb232c55","repo":"payloadcms/payload","slug":"invalid-upload-instructions-request","errorCode":null,"errorMessage":"Invalid upload instructions request","messagePattern":"Invalid upload instructions request","errorType":"http","errorClass":"APIError","httpStatus":400,"severity":"error","filePath":"packages/payload/src/uploads/endpoints/uploadInstructions.ts","lineNumber":97,"sourceCode":"    if (!collectionPermissions?.create && !collectionPermissions?.update) {\n      throw new Forbidden(req.t)\n    }\n  }\n\n  return uploadInstructions\n    ? uploadInstructions.generate({ ...upload, overrideAccess, req })\n    : generateStagedUploadInstructions({ ...upload, req })\n}\n\nexport const uploadInstructionsEndpoint: Endpoint = {\n  handler: async (req) => {\n    if (!req.json) {\n      throw new APIError('Content-Type expected to be application/json', 400)\n    }\n\n    const upload: unknown = await req.json()\n    if (!isUploadInstructionsRequest(upload)) {\n      throw new APIError('Invalid upload instructions request', 400)\n    }\n\n    return Response.json(await getUploadInstructions({ ...upload, req }))\n  },\n  method: 'post',\n  path: '/upload-instructions',\n}\n\n/**\n * Stores or removes temporary files when no adapter-specific upload instructions are available.\n * PUT keeps the file until it is used in a document request.\n * DELETE removes a file the client no longer needs.\n */\nexport const stagedUploadEndpoints: Endpoint[] = [\n  {\n    handler: uploadStagedFile,\n    method: 'put',\n    path: '/upload-instructions/:uploadId',","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/payloadcms/payload/blob/00c58b35c0ed348ddc22daabf467b139727214fd/packages/payload/src/uploads/endpoints/uploadInstructions.ts#L79-L115","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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`.","solutions":["Validate the payload against `UploadInstructionsRequest` (collectionSlug/filename/mimeType strings, filesize a non-negative safe integer) before sending.","Coerce `filesize` to `Math.max(0, Math.trunc(Number(filesize)))` and guard `Number.isSafeInteger`.","Sync client types with the server's `UploadInstructionsRequest` interface from `payload`.","Ensure the body is a flat object, not nested under a wrapper key."],"exampleFix":"// before\nfetch(`${url}/api/upload-instructions`, {\n  method: 'POST',\n  headers: { 'Content-Type': 'application/json' },\n  body: JSON.stringify({\n    collection: 'media',          // wrong key (should be collectionSlug)\n    filename: 'a.png',\n    filesize: '2048',             // string, not number\n    mimeType: 'image/png',\n  }),\n})\n\n// after\nconst payload = {\n  collectionSlug: 'media',\n  filename: 'a.png',\n  filesize: 2048,                 // number, safe integer >= 0\n  mimeType: 'image/png',\n}\nfetch(`${url}/api/upload-instructions`, {\n  method: 'POST',\n  headers: { 'Content-Type': 'application/json' },\n  body: JSON.stringify(payload),\n})","handlingStrategy":"type-guard","validationCode":"function isUploadInstructionsRequest(u: unknown): u is UploadInstructionsRequest {\n  if (!u || typeof u !== 'object') return false\n  const o = u as Record<string, unknown>\n  return (\n    typeof o.collectionSlug === 'string' &&\n    typeof o.filename === 'string' &&\n    typeof o.mimeType === 'string' &&\n    typeof o.filesize === 'number' &&\n    Number.isSafeInteger(o.filesize) &&\n    o.filesize >= 0 &&\n    (o.docPrefix === undefined || typeof o.docPrefix === 'string')\n  )\n}\n\nconst body = { collectionSlug: 'media', filename, filesize: Math.trunc(file.size), mimeType }\nif (!isUploadInstructionsRequest(body)) {\n  throw new Error('Invalid upload-instructions payload')\n}","typeGuard":"const isUploadInstructionsRequest = (u: unknown): u is UploadInstructionsRequest =>\n  !!u && typeof u === 'object' &&\n  typeof (u as any).collectionSlug === 'string' &&\n  typeof (u as any).filename === 'string' &&\n  typeof (u as any).mimeType === 'string' &&\n  typeof (u as any).filesize === 'number' &&\n  Number.isSafeInteger((u as any).filesize) &&\n  (u as any).filesize >= 0","tryCatchPattern":"try {\n  if (!isUploadInstructionsRequest(payload)) throw new Error('bad shape')\n  await fetch(`${url}/api/upload-instructions`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) })\n} catch (err) {\n  if (/invalid upload instructions request/i.test(String(err))) {\n    // fix field types and retry\n  }\n}","preventionTips":["Share the `UploadInstructionsRequest` type from `payload` with the client.","Coerce `filesize` to a non-negative safe integer before sending.","Reject bodies where optional `docPrefix` is a non-string."],"tags":["upload","type-validation","http","request-shape"],"backgroundTag":null,"analyzedSha":"00c58b35c0ed348ddc22daabf467b139727214fd","analyzedAt":"2026-08-12T20:45:03.758Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}