payloadcms/payload · error · Forbidden
error:notAllowedToPerformAction
Error message
error:notAllowedToPerformAction
What it means
Thrown in `unlock` when `collectionConfig.auth.disableLocalStrategy` is true. With no local credential store there is nothing to lock/unlock, so the operation refuses. `Forbidden` (HTTP 403).
Source
Thrown at packages/payload/src/auth/operations/unlock.ts:52
overrideAccess,
req: { locale },
req,
} = args
const loginWithUsername = collectionConfig.auth.loginWithUsername
const { canLoginWithEmail, canLoginWithUsername } = getLoginOptions(loginWithUsername)
const sanitizedEmail = canLoginWithEmail && (args.data?.email || '').toLowerCase().trim()
const sanitizedUsername =
(canLoginWithUsername &&
'username' in args.data &&
typeof args.data.username === 'string' &&
args.data.username.toLowerCase().trim()) ||
null
if (collectionConfig.auth.disableLocalStrategy) {
throw new Forbidden(req.t)
}
if (!sanitizedEmail && !sanitizedUsername) {
throw new APIError(
`Missing ${collectionConfig.auth.loginWithUsername ? 'username' : 'email'}.`,
httpStatus.BAD_REQUEST,
)
}
try {
args = await buildBeforeOperation({
args,
collection: args.collection.config,
operation: 'unlock',
overrideAccess,
})
const shouldCommit = await initTransaction(req)
let whereConstraint: Where = {}View on GitHub (pinned to 00c58b35c0)
Solutions
- Only call unlock on collections with a local strategy (`disableLocalStrategy: false`).
- For external-strategy collections, manage lock/unlock through the IdP.
- Branch your code on `collectionConfig.auth.disableLocalStrategy` before invoking unlock.
Example fix
// before
await payload.unlock({ collection, data, req })
// after
if (!collectionConfig.auth.disableLocalStrategy) {
await payload.unlock({ collection, data, req })
} Defensive patterns
Strategy: validation
Validate before calling
// Skip unlock for external-strategy collections
if (collectionConfig.auth.disableLocalStrategy) {
throw new Error('Unlock is unavailable for this collection')
}
await payload.unlock({ collection, data, req }) Type guard
function supportsUnlock(cfg: CollectionConfig): boolean {
return !cfg.auth?.disableLocalStrategy
} Try / catch
if (collectionConfig.auth.disableLocalStrategy) {
// manage lock state via the IdP
} else {
await payload.unlock({ collection, data, req })
} Prevention
- Branch unlock UI on `disableLocalStrategy`.
- Keep external-strategy collections out of local lockout flows.
- Document strategy per collection in setup docs.
When it happens
Trigger: A collection configured with `auth: { disableLocalStrategy: true }` receives an unlock request (`POST /api/<collection>/unlock` or Local API `payload.unlock`). The guard fires before any lookup.
Common situations: Shared unlock UI/flow that doesn't branch on strategy; misconfigured collection that should support local lockout; calling the wrong collection slug for unlock.
Related errors
- error:notAllowedToPerformAction
- error:notAllowedToPerformAction
- error:notAllowedToPerformAction
- Missing ${collectionConfig.auth.loginWithUsername ? 'usernam
- No auth config found for collection: ${collection}
AI-assisted analysis of payloadcms/payload@00c58b35c0 (2026-08-12).
Data as JSON: /api/errors/2233784bff9715eb.
Report an issue: GitHub.