payloadcms/payload · error · APIError
Staged upload was not found.
Error message
Staged upload was not found.
What it means
Thrown by `getStagedFile` when reading the temp file from disk fails (the `fs.readFile` call rejects). The staged upload JWT is valid and the user/collection match, but the underlying file on disk is gone.
Source
Thrown at packages/payload/src/uploads/stagedUpload.ts:178
) {
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)
}
if (data.length !== upload.filesize) {
await fs.rm(tempFilePath, { force: true })
throw new APIError('Staged upload is incomplete.', 400)
}
await fs.rm(tempFilePath, { force: true })
return {
name: upload.filename,
data,
mimetype: upload.mimeType,
size: data.length,
}
}
/**View on GitHub (pinned to 00c58b35c0)
Solutions
- Treat an uploadId as single-use: stage -> PUT bytes -> consume once. Do not retry the document create with the same uploadId.
- If the operation failed transiently, re-stage the file from scratch (new instructions, re-upload bytes).
- Ensure persistent or sufficiently long-lived temp storage if your workflow may delay the document create beyond a few minutes.
- Check that `upload.tempFileDir` is not pointing at a container-local path that is lost on redeploy.
Example fix
// before -- retrying create with same uploadId after a transient failure
try { await createWithUpload(uploadId) } catch { await createWithUpload(uploadId) } // 2nd call: file gone
// after -- re-stage on failure
try {
await createWithUpload(uploadId)
} catch {
const instr = await generateStagedUploadInstructions({ ... })
await putBytes(instr)
await createWithUpload(instr.file.uploadReference.uploadId)
} Defensive patterns
Strategy: try-catch
Validate before calling
// Before consuming, ensure you are within the 1-hour window
const elapsed = Date.now() - stagedAt
if (elapsed > 55 * 60 * 1000) {
// re-stage before it expires
} Try / catch
try {
await payload.create({ collection, data })
} catch (e) {
if (e instanceof APIError && e.message === 'Staged upload was not found.') {
// file is gone -- must re-stage from scratch
const fresh = await generateStagedUploadInstructions({ ... })
await putStagedBytes(fresh)
await payload.create({ collection, data: { ...data, file: { uploadReference: { uploadId: fresh.file.uploadReference.uploadId } } } })
} else throw e
} Prevention
- Treat each uploadId as single-use: stage -> PUT -> consume exactly once.
- Complete the full flow within the one-hour token window.
- Do not retry document creation with the same uploadId.
When it happens
Trigger: The temp file was already consumed and deleted by a prior `getStagedFile` call (each call deletes the file), or `removeExpiredUploads` cleaned it up after the one-hour window, or the temp directory was cleared by an external process / container restart.
Common situations: Calling create/update twice with the same uploadId (second call finds no file); the server restarted and temp files are on ephemeral storage; the one-hour JWT window expired and the cleanup sweeper removed the file; a deployment wiped the `tempFileDir`.
Related errors
- Upload collection ${upload.collectionSlug} was not found
- You are not allowed to perform this action.
- Uploaded file is larger than expected.
- Uploaded file size does not match the expected size.
- Invalid staged upload.
AI-assisted analysis of payloadcms/payload@00c58b35c0 (2026-08-12).
Data as JSON: /api/errors/467103cdea5b17ad.
Report an issue: GitHub.