payloadcms/payload · error · APIError
No User
Error message
No User
What it means
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.
Source
Thrown at packages/payload/src/auth/operations/logout.ts:28
import { killTransaction } from '../../utilities/killTransaction.js'
export type Arguments = {
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
}
}View on GitHub (pinned to 00c58b35c0)
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.
Example fix
// before
await payload.logout({ collection: 'users', req: createLocalReq({}, payload) })
// after
const req = await createLocalReq({ user: loggedInUser }, payload)
await payload.logout({ collection: 'users', req }) Defensive patterns
Strategy: validation
Validate before calling
// Before logout, ensure a user is attached to the request
if (!req.user) {
// nothing to log out; clear client state locally
return clearLocalSession()
}
await payload.logout({ collection: req.user.collection, req }) Type guard
// Narrow the request to an authenticated one before calling logout
function isAuthenticatedReq(req: PayloadRequest): req is PayloadRequest & { user: User } {
return !!req.user && typeof req.user.collection === 'string'
} Try / catch
try {
await payload.logout({ collection, req })
} catch (e) {
if (e instanceof APIError && e.status === 400 && e.message === 'No User') {
// no active session — clear client token
} else throw e
} Prevention
- 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.
When it happens
Trigger: 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).
Common situations: 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`.
Related errors
- Incorrect collection
- error:notAllowedToPerformAction
- Cannot refresh token: user not authenticated
- No auth config found for collection: ${collection}
- Username or email is required
AI-assisted analysis of payloadcms/payload@00c58b35c0 (2026-08-12).
Data as JSON: /api/errors/22664ec517d31868.
Report an issue: GitHub.