payloadcms/payload · error · APIError

Incorrect collection

Error message

Incorrect collection

What it means

Thrown when `user.collection !== collectionConfig.slug` — the authenticated user's JWT was minted for a different collection than the one the logout route targets. Payload supports multiple auth collections, and each logout endpoint is scoped to one collection slug. Mismatch is rejected with HTTP 403. This prevents cross-collection session tampering.

Source

Thrown at packages/payload/src/auth/operations/logout.ts:31

  allSessions?: boolean
  collection: Collection
  req: PayloadRequest
}

export const logoutOperation = async (incomingArgs: Arguments): Promise<boolean> => {
  let args = incomingArgs
  const {
    allSessions,
    collection: { config: collectionConfig },
    req: { user },
    req,
  } = incomingArgs

  if (!user) {
    throw new APIError('No User', httpStatus.BAD_REQUEST)
  }
  if (user.collection !== collectionConfig.slug) {
    throw new APIError('Incorrect collection', httpStatus.FORBIDDEN)
  }

  const shouldCommit = await initTransaction(req)

  try {
    if (collectionConfig.hooks?.afterLogout?.length) {
      for (const hook of collectionConfig.hooks.afterLogout) {
        args =
          (await hook({
            collection: args.collection?.config,
            context: req.context,
            req,
          })) || args
      }
    }

    if (collectionConfig.auth.disableLocalStrategy !== true && collectionConfig.auth.useSessions) {
      const where = appendNonTrashedFilter({

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Use the same collection slug the user logged in with: derive it from `req.user.collection` instead of hard-coding.
  2. Ensure the frontend logout call targets the collection that owns the token, e.g. `/api/${userCollection}/logout`.
  3. If calling the Local API, read `req.user.collection` and pass that slug.

Example fix

// before
await payload.logout({ collection: 'admins', req })
// after
await payload.logout({ collection: req.user.collection, req })
Defensive patterns

Strategy: validation

Validate before calling

// Use the collection the token actually belongs to
const slug = req.user?.collection ?? targetCollection
if (req.user && req.user.collection !== slug) {
  throw new Error(`Logout target ${slug} does not match authenticated collection ${req.user.collection}`)
}

Type guard

function userMatchesCollection(user: User, slug: string): boolean {
  return user.collection === slug
}

Try / catch

try {
  await payload.logout({ collection: req.user.collection, req })
} catch (e) {
  if (e instanceof APIError && e.message === 'Incorrect collection') {
    // re-route logout to the correct collection slug
  } else throw e
}

Prevention

When it happens

Trigger: A user authenticated against the `customers` collection hits `POST /api/admins/logout` (or vice-versa). Programmatically: `payload.logout({ collection: 'admins', req })` where `req.user.collection === 'customers'`.

Common situations: A monorepo/frontend hard-codes the wrong collection slug in the logout URL after splitting auth into multiple collections; copy-pasting a logout call across collection contexts; a JWT from a staging environment's other collection leaking into the client.

Related errors


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