payloadcms/payload · error · APIError
Invalid staged upload.
Error message
Invalid staged upload.
What it means
Thrown by `getStagedFile` when the `uploadReference` object passed to a document create/update is structurally invalid -- it must be a non-null, non-array object containing a string `uploadId`. This reference is what links a document mutation to the bytes previously staged via the signed upload URL.
Source
Thrown at packages/payload/src/uploads/stagedUpload.ts:161
* it, and the temporary file is deleted after it is read.
*/
export const getStagedFile = async ({
collectionSlug,
req,
uploadReference,
}: {
collectionSlug: string
req: PayloadRequest
uploadReference: unknown
}): Promise<File> => {
if (
!uploadReference ||
typeof uploadReference !== 'object' ||
Array.isArray(uploadReference) ||
!('uploadId' in uploadReference) ||
typeof uploadReference.uploadId !== 'string'
) {
throw new APIError('Invalid staged upload.', 400)
}
const { uploadId } = uploadReference
const upload = await verifyUploadID(req, uploadId)
if (upload.collectionSlug !== collectionSlug || upload.user !== getUser(req)) {
throw new Forbidden(req.t)
}
const directory = await getUploadDirectory(req, upload.collectionSlug)
const tempFilePath = path.join(directory, upload.id)
let data: Buffer
try {
data = await fs.readFile(tempFilePath)
} catch {
throw new APIError('Staged upload was not found.', 400)
}View on GitHub (pinned to 00c58b35c0)
Solutions
- Pass the `uploadReference` object exactly as returned by `generateStagedUploadInstructions` -- do not reconstruct it.
- Ensure the value is JSON-serializable and survives any FormData / nested-field encoding (check that nested objects are not stringified twice or flattened).
- Validate the shape client-side before the request (see validationCode).
- If migrating from a legacy upload flow, update the client to use the staged-upload `uploadReference` shape.
Example fix
// before
await payload.create({
collection: 'media',
data: { file: { uploadReference: myUploadId } }, // uploadId at wrong level
})
// after
const instructions = await payloadUploadApi.getInstructions(...)
await payload.create({
collection: 'media',
data: {
file: { uploadReference: { uploadId: instructions.file.uploadReference.uploadId } },
},
}) Defensive patterns
Strategy: type-guard
Validate before calling
// Validate the uploadReference shape before sending
function isValidUploadReference(v) {
return !!v && typeof v === 'object' && !Array.isArray(v)
&& 'uploadId' in v && typeof v.uploadId === 'string'
}
if (!isValidUploadReference(file.uploadReference)) {
throw new Error('uploadReference must be { uploadId: string }')
} Type guard
const isUploadReference = (v) => !!v && typeof v === 'object' && !Array.isArray(v) && 'uploadId' in v && typeof v.uploadId === 'string'
Try / catch
try {
await payload.create({ collection, data })
} catch (e) {
if (e instanceof APIError && e.message === 'Invalid staged upload.') {
// regenerate instructions and retry
} else throw e
} Prevention
- Echo back the uploadReference object exactly as returned by generateStagedUploadInstructions.
- Add a client-side type guard before submitting the document create/update.
- Avoid manually constructing the uploadReference; always use the SDK-provided value.
When it happens
Trigger: A create/update request sends `file: { uploadReference: ... }` where `uploadReference` is undefined, a primitive, an array, missing the `uploadId` key, or has a non-string `uploadId`.
Common situations: Client code constructs the `uploadReference` manually instead of echoing back the object from `generateStagedUploadInstructions`; a serialization layer (e.g. FormData) dropped the nested object; the client is using an older API shape that passed a plain filename string.
Related errors
- Upload collection ${upload.collectionSlug} was not found
- Uploaded file is larger than expected.
- Uploaded file size does not match the expected size.
- 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/e1eea04d37da11aa.
Report an issue: GitHub.