{"record":{"id":"2233784bff9715eb","repo":"payloadcms/payload","slug":"error-notallowedtoperformaction-223378","errorCode":null,"errorMessage":"error:notAllowedToPerformAction","messagePattern":"error:notAllowedToPerformAction","errorType":"exception","errorClass":"Forbidden","httpStatus":403,"severity":"error","filePath":"packages/payload/src/auth/operations/unlock.ts","lineNumber":52,"sourceCode":"    overrideAccess,\n    req: { locale },\n    req,\n  } = args\n\n  const loginWithUsername = collectionConfig.auth.loginWithUsername\n\n  const { canLoginWithEmail, canLoginWithUsername } = getLoginOptions(loginWithUsername)\n\n  const sanitizedEmail = canLoginWithEmail && (args.data?.email || '').toLowerCase().trim()\n  const sanitizedUsername =\n    (canLoginWithUsername &&\n      'username' in args.data &&\n      typeof args.data.username === 'string' &&\n      args.data.username.toLowerCase().trim()) ||\n    null\n\n  if (collectionConfig.auth.disableLocalStrategy) {\n    throw new Forbidden(req.t)\n  }\n  if (!sanitizedEmail && !sanitizedUsername) {\n    throw new APIError(\n      `Missing ${collectionConfig.auth.loginWithUsername ? 'username' : 'email'}.`,\n      httpStatus.BAD_REQUEST,\n    )\n  }\n\n  try {\n    args = await buildBeforeOperation({\n      args,\n      collection: args.collection.config,\n      operation: 'unlock',\n      overrideAccess,\n    })\n\n    const shouldCommit = await initTransaction(req)\n    let whereConstraint: Where = {}","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/payloadcms/payload/blob/00c58b35c0ed348ddc22daabf467b139727214fd/packages/payload/src/auth/operations/unlock.ts#L34-L70","documentation":"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).","triggerScenarios":"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.","commonSituations":"Shared unlock UI/flow that doesn't branch on strategy; misconfigured collection that should support local lockout; calling the wrong collection slug for unlock.","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."],"exampleFix":"// before\nawait payload.unlock({ collection, data, req })\n// after\nif (!collectionConfig.auth.disableLocalStrategy) {\n  await payload.unlock({ collection, data, req })\n}","handlingStrategy":"validation","validationCode":"// Skip unlock for external-strategy collections\nif (collectionConfig.auth.disableLocalStrategy) {\n  throw new Error('Unlock is unavailable for this collection')\n}\nawait payload.unlock({ collection, data, req })","typeGuard":"function supportsUnlock(cfg: CollectionConfig): boolean {\n  return !cfg.auth?.disableLocalStrategy\n}","tryCatchPattern":"if (collectionConfig.auth.disableLocalStrategy) {\n  // manage lock state via the IdP\n} else {\n  await payload.unlock({ collection, data, req })\n}","preventionTips":["Branch unlock UI on `disableLocalStrategy`.","Keep external-strategy collections out of local lockout flows.","Document strategy per collection in setup docs."],"tags":["auth","unlock","sso","config"],"backgroundTag":null,"analyzedSha":"00c58b35c0ed348ddc22daabf467b139727214fd","analyzedAt":"2026-08-12T20:45:03.758Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}