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

The slug field's server-side slugify handler throws UnauthorizedError when `req.user` is absent. Generating a unique slug probes the collection for collisions via `getUniqueFieldValue`, which requires an authenticated admin session, so the handler rejects anonymous requests before reading field config or touching the DB. This is a deliberate auth gate, not an accidental failure.

Source

Thrown at packages/ui/src/utilities/slugify.ts:33

/**
 * This server function is directly related to the {@link https://payloadcms.com/docs/fields/slug | Slug Field}.
 * This is a server function that is used to invoke the user's custom slugify function from the client.
 * This pattern is required, as there is no other way for us to pass their function across the client-server boundary.
 *   - Not through props
 *   - Not from a server function defined within a server component (see below)
 * When a server function contains non-serializable data within its closure, it gets passed through the boundary (and breaks).
 * The only way to pass server functions to the client (that contain non-serializable data) is if it is globally defined.
 * But we also cannot define this function alongside the server component, as we will not have access to their custom slugify function.
 * See `ServerFunctionsProvider` for more details.
 */
export const slugifyHandler: ServerFunction<
  SlugifyServerFunctionArgs,
  Promise<ReturnType<Slugify>>
> = async (args) => {
  const { id, collectionSlug, data, globalSlug, locale, path, req, valueToSlugify } = args

  if (!req.user) {
    throw new UnauthorizedError()
  }

  const docConfig = collectionSlug
    ? req.payload.collections[collectionSlug]?.config
    : globalSlug
      ? req.payload.config.globals.find((g) => g.slug === globalSlug)
      : null

  if (!docConfig) {
    throw new Error()
  }

  const { field } = getFieldByPath({
    config: req.payload.config,
    fields: docConfig.flattenedFields,
    path,
  })

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Ensure the user is logged in and the session is still valid before editing a slug field.
  2. Verify the auth cookie is sent with the server-function request (credentials: 'include' / same-origin).
  3. Confirm the configured auth strategy populates `req.user` for admin routes.
  4. Re-authenticate the user and retry the slug generation.
Defensive patterns

Strategy: validation

Validate before calling

if (!req.user) {
  // surface 'login required' / redirect to /admin/login before invoking slugify
}

Type guard

function isAuthenticated<
  R extends { user?: unknown },
>(req: R): req is R & { user: NonNullable<R['user']> } {
  return !!req.user
}

Try / catch

import { UnauthorizedError } from 'payload'

try {
  await slugify(args)
} catch (err) {
  if (err instanceof UnauthorizedError) {
    // session expired - prompt re-login, then retry
  } else {
    throw err
  }
}

Prevention

When it happens

Trigger: Slug auto-generation triggered after the admin session expired, the auth cookie not sent on the server-function fetch, a custom auth strategy that does not populate `req.user`, accessing the admin slug field while logged out.

Common situations: Long-idle admin tabs whose session lapsed, cross-origin server-function requests sent without credentials, auth plugin misconfiguration leaving `req.user` undefined, load-balancer/proxy stripping cookies.

Understand the failure class

Related errors


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