payloadcms/payload · error · Forbidden
You are not allowed to perform this action.
Error message
You are not allowed to perform this action.
What it means
Thrown as `new Forbidden(req.t)` (HTTP 403) at packages/payload/src/collections/operations/restoreVersion.ts:129 during restoreVersion when the parent document is not found AND a where-based access policy is in effect. The distinction from error 155 matters: when access control returns a `where` clause and the doc is absent, Payload reports Forbidden (not NotFound) to avoid leaking the existence of documents the user cannot see.
Source
Thrown at packages/payload/src/collections/operations/restoreVersion.ts:129
// /////////////////////////////////////
// Retrieve document
// /////////////////////////////////////
const findOneArgs: FindOneArgs = {
collection: collectionConfig.slug,
locale: 'all',
req,
where: combineQueries({ id: { equals: parentDocID } }, accessResults),
}
// Get the document from the non versioned collection
const doc = await req.payload.db.findOne<TData>(findOneArgs)
if (!doc && !hasWherePolicy) {
throw new NotFound(req.t)
}
if (!doc && hasWherePolicy) {
throw new Forbidden(req.t)
}
if (collectionConfig.trash && doc?.deletedAt) {
throw new APIError(
`Cannot restore a version of a trashed document (ID: ${parentDocID}). Restore the document first.`,
httpStatus.FORBIDDEN,
)
}
// /////////////////////////////////////
// fetch previousDoc
// /////////////////////////////////////
const prevDocWithLocales = await getLatestCollectionVersion({
id: parentDocID,
config: collectionConfig,
payload,
query: findOneArgs,
req,View on GitHub (pinned to 00c58b35c0)
Solutions
- Confirm the authenticated user has `update` access to the parent document's collection.
- Inspect the collection's `access.update` function and the where clause it returns for this user.
- If overriding access server-side is acceptable, pass `overrideAccess: true` (use sparingly and never with untrusted callers).
Example fix
// before — user lacks update access, restoreVersion throws Forbidden
await payload.restoreVersion({ collection: 'pages', id: versionId, req })
// after — escalate to a service account that is allowed to update, or fix the access policy
await payload.restoreVersion({ collection: 'pages', id: versionId, overrideAccess: true, req })
// (only in trusted server contexts; never expose overrideAccess:true to client input) Defensive patterns
Strategy: try-catch
Validate before calling
// Access policies are server-side; the reliable pre-check is a findByID with the user's req
const visible = await payload.findByID({
collection: 'pages',
id: parentDocID,
req, // applies the user's access.update where policy
disableErrors: true,
})
if (!visible) {
// user cannot see/update this document — do not attempt restoreVersion
} Type guard
// No static type guard applies; access is runtime-evaluated.
// Expose a helper that runs the access check:
const canRestore = async (payload: Payload, collection: CollectionSlug, parentId: string | number, req: PayloadRequest) => {
const doc = await payload.findByID({ collection, id: parentId, req, disableErrors: true })
return Boolean(doc)
} Try / catch
try {
await payload.restoreVersion({ collection: 'pages', id: versionId, req })
} catch (err) {
if (err instanceof Forbidden) {
// user lacks update access (or doc hidden by a where policy) — return 403
} else throw err
} Prevention
- Never expose overrideAccess:true to client input; only use it in trusted server code.
- Test restore flows under each role defined in access.update.
- When access returns a where clause, treat 'not found' as 403 to avoid information leakage (Payload already does this internally).
When it happens
Trigger: A user without update access attempts to restore a version of a document they cannot read; the collection's `access.update` returns a where filter that excludes the parent doc; the parent doc was deleted but the access policy is a where clause (so 403 is chosen over 404 to prevent information disclosure).
Common situations: Role-based access where the user's policy hides certain docs; a multi-tenant where clause (`tenant: { equals: currentUser.tenant }`) that does not match the version's parent; restoring across locales/tenants.
Related errors
- Cannot restore a version of a trashed document (ID: ${parent
- You are not allowed to perform this action.
- You are not allowed to perform this action.
- You are not allowed to perform this action.
- You are not allowed to perform this action.
AI-assisted analysis of payloadcms/payload@00c58b35c0 (2026-08-12).
Data as JSON: /api/errors/ddcdd08720892b19.
Report an issue: GitHub.