{"record":{"id":"22664ec517d31868","repo":"payloadcms/payload","slug":"no-user","errorCode":null,"errorMessage":"No User","messagePattern":"No User","errorType":"exception","errorClass":"APIError","httpStatus":400,"severity":"error","filePath":"packages/payload/src/auth/operations/logout.ts","lineNumber":28,"sourceCode":"import { killTransaction } from '../../utilities/killTransaction.js'\n\nexport type Arguments = {\n  allSessions?: boolean\n  collection: Collection\n  req: PayloadRequest\n}\n\nexport const logoutOperation = async (incomingArgs: Arguments): Promise<boolean> => {\n  let args = incomingArgs\n  const {\n    allSessions,\n    collection: { config: collectionConfig },\n    req: { user },\n    req,\n  } = incomingArgs\n\n  if (!user) {\n    throw new APIError('No User', httpStatus.BAD_REQUEST)\n  }\n  if (user.collection !== collectionConfig.slug) {\n    throw new APIError('Incorrect collection', httpStatus.FORBIDDEN)\n  }\n\n  const shouldCommit = await initTransaction(req)\n\n  try {\n    if (collectionConfig.hooks?.afterLogout?.length) {\n      for (const hook of collectionConfig.hooks.afterLogout) {\n        args =\n          (await hook({\n            collection: args.collection?.config,\n            context: req.context,\n            req,\n          })) || args\n      }\n    }","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/payloadcms/payload/blob/00c58b35c0ed348ddc22daabf467b139727214fd/packages/payload/src/auth/operations/logout.ts#L10-L46","documentation":"Thrown at the top of the logout operation when `req.user` is falsy. Payload resolves the authenticated user from the JWT/cookie middleware before the operation runs, so reaching this throw means no valid credential reached the handler. It surfaces as an APIError with HTTP 400 (BAD_REQUEST). It exists because logout is meaningless without a session to destroy.","triggerScenarios":"A client calls the logout endpoint (e.g. `POST /api/<collection>/logout`) with no `payload-token` cookie/`Authorization` header, or with an already-expired token. It also occurs when calling `payload.logout()` via the Local API with a `req` that has no `user` attached (e.g. a `createLocalReq({})` without injecting credentials).","commonSituations":"Frontend logs the token out then immediately retries logout; the auth middleware is misconfigured or skipped for that route; a proxy/gateway strips the cookie header; a custom Local API script forgets to pass the authenticated `req`.","solutions":["Confirm the request reaches Payload with a valid `payload-token` cookie or `Authorization: JWT <token>` header.","If using the Local API, pass the authenticated request object: `await payload.logout({ collection, req: authenticatedReq })` rather than a fresh `createLocalReq({})`.","Check that `config.csrf` / cookie `sameSite` and the reverse proxy are not dropping the cookie.","Verify the JWT has not already expired before issuing the logout call."],"exampleFix":"// before\nawait payload.logout({ collection: 'users', req: createLocalReq({}, payload) })\n// after\nconst req = await createLocalReq({ user: loggedInUser }, payload)\nawait payload.logout({ collection: 'users', req })","handlingStrategy":"validation","validationCode":"// Before logout, ensure a user is attached to the request\nif (!req.user) {\n  // nothing to log out; clear client state locally\n  return clearLocalSession()\n}\nawait payload.logout({ collection: req.user.collection, req })","typeGuard":"// Narrow the request to an authenticated one before calling logout\nfunction isAuthenticatedReq(req: PayloadRequest): req is PayloadRequest & { user: User } {\n  return !!req.user && typeof req.user.collection === 'string'\n}","tryCatchPattern":"try {\n  await payload.logout({ collection, req })\n} catch (e) {\n  if (e instanceof APIError && e.status === 400 && e.message === 'No User') {\n    // no active session — clear client token\n  } else throw e\n}","preventionTips":["Always forward the authenticated `req` (or its token) into logout calls.","Have the client clear local session state even when the server call reports no user.","Confirm cookie/header passthrough through proxies and CORS settings."],"tags":["auth","logout","session","middleware"],"backgroundTag":null,"analyzedSha":"00c58b35c0ed348ddc22daabf467b139727214fd","analyzedAt":"2026-08-12T20:45:03.758Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}