payloadcms/payload · error · UnauthorizedError

Unauthorized, you must be logged in to make this request.

Error message

Unauthorized, you must be logged in to make this request.

What it means

Thrown by `canAccessAdmin` when the authenticated user collection defines an `access.admin` function and that function returns a falsy value. This is the primary, customizable admin-access gate -- it runs per-request on admin-protected routes and server functions.

Source

Thrown at packages/payload/src/utilities/canAccessAdmin.ts:24

 * Protects admin-only routes, server functions, etc.
 * The requesting user must either:
 * a. pass the `access.admin` function on the `users` collection, if defined
 * b. match the `config.admin.user` property on the Payload config
 * c. if no user is present, and there are no users in the system, allow access (for first user creation)
 * @throws {Error} Throws an `Unauthorized` error if access is denied that can be explicitly caught
 */
export const canAccessAdmin = async ({ req }: { req: PayloadRequest }) => {
  const incomingUserSlug = req.user?.collection
  const adminUserSlug = req.payload.config.admin.user

  if (incomingUserSlug) {
    const adminAccessFn = req.payload.collections[incomingUserSlug]?.config.access?.admin

    if (adminAccessFn) {
      const canAccess = await adminAccessFn({ slug: incomingUserSlug, req })

      if (!canAccess) {
        throw new UnauthorizedError()
      }
      // Match the user collection to the global admin config
    } else if (adminUserSlug !== incomingUserSlug) {
      throw new UnauthorizedError()
    }
  } else {
    const hasUsers = await req.payload.find({
      collection: adminUserSlug,
      depth: 0,
      limit: 1,
      pagination: false,
    })

    // If there are users, we should not allow access because of `/create-first-user`
    if (hasUsers.docs.length) {
      throw new UnauthorizedError()
    }
  }

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Inspect the collection `access.admin` function logic and verify the user document satisfies its conditions.
  2. Ensure the user document has the role/permission field the function checks.
  3. Test the function in isolation with the actual `req.user` object.
  4. Update the `access.admin` implementation if the role model changed.

Example fix

// before
access: {
  admin: ({ req }) => req.user.role === 'admin', // user has 'roles' array, not 'role'
}

// after
access: {
  admin: ({ req }) => Array.isArray(req.user?.roles) && req.user.roles.includes('admin'),
}
Defensive patterns

Strategy: validation

Validate before calling

// Before making the admin request, verify the user passes the access.admin check
const adminAccessFn = collectionConfig.access?.admin
if (adminAccessFn) {
  const ok = await adminAccessFn({ slug: user.collection, req: syntheticReq })
  if (!ok) throw new Error('User fails access.admin check')
}

Try / catch

try {
  await adminAction()
} catch (e) {
  if (e instanceof UnauthorizedError) {
    // inspect access.admin logic; ensure user has required role/permission
  } else throw e
}

Prevention

When it happens

Trigger: A logged-in user whose collection config includes `access: { admin: ({ req }) => boolean }` makes a request to an admin-gated route or server function, and the function evaluates to `false` (e.g. a role check fails).

Common situations: The `access.admin` function checks a role/permission field that is missing or wrong on the user document; a migration changed the user role field name; the function has a bug (e.g. `req.user.role === 'writer'` when the field is `req.user.roles` array); the user was created before the access logic was added and lacks the required attribute.

Understand the failure class

Related errors


AI-assisted analysis of payloadcms/payload@00c58b35c0 (2026-08-12). Data as JSON: /api/errors/31036a16adeb5192. Report an issue: GitHub.