{"record":{"id":"f41a5a1a6fcc0ebf","repo":"payloadcms/payload","slug":"unauthorized-you-must-be-logged-in-to-make-this-r-f41a5a","errorCode":null,"errorMessage":"Unauthorized, you must be logged in to make this request.","messagePattern":"Unauthorized, you must be logged in to make this request\\.","errorType":"exception","errorClass":"UnauthorizedError","httpStatus":401,"severity":"error","filePath":"packages/ui/src/utilities/buildFormState.ts","lineNumber":81,"sourceCode":"> = async (args) => {\n  const { req } = args\n\n  try {\n    await canAccessAdmin({ req })\n    const res = await buildFormState(args)\n\n    return res\n  } catch (err) {\n    req.payload.logger.error({ err, msg: `There was an error building form state` })\n\n    if (err.message === 'Could not find field schema for given path') {\n      return {\n        message: err.message,\n      }\n    }\n\n    if (err.message === 'Unauthorized') {\n      throw new UnauthorizedError()\n    }\n\n    return formatErrors(err)\n  }\n}\n\nexport const buildFormState = async (\n  args: BuildFormStateArgs,\n): Promise<BuildFormStateSuccessResult> => {\n  const {\n    id: idFromArgs,\n    checkForStaleData,\n    collectionSlug,\n    data: incomingData,\n    docPermissions,\n    docPreferences,\n    documentFormState,\n    formState,","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/payloadcms/payload/blob/00c58b35c0ed348ddc22daabf467b139727214fd/packages/ui/src/utilities/buildFormState.ts#L63-L99","documentation":"Thrown as UnauthorizedError (HTTP 401) by buildFormState's catch block when a downstream function threw a plain Error whose message is exactly 'Unauthorized'. buildFormState wraps form-state construction; if any inner step (e.g. a server function like renderTab) throws the generic 'Unauthorized' string, this wrapper promotes it to a proper 401 UnauthorizedError.","triggerScenarios":"During form-state building, a nested operation throws new Error('Unauthorized') (the bare-string pattern from errors 391/393), and buildFormState's catch detects that exact message and re-throws UnauthorizedError.","commonSituations":"Session expired mid form-state build; a nested server function (renderTab/renderField) hit its !req.user guard; auth not propagated into a sub-call during form-state construction.","solutions":["Ensure the admin session is valid before the form-state build is triggered.","Make sure nested server functions invoked during form-state build receive the authenticated req.user.","Treat the 401 in the client as a signal to redirect to login and re-fetch form state."],"exampleFix":"// before — inner function throws bare string\nif (!req.user) throw new Error('Unauthorized')\n\n// after — throw the typed error so callers can instanceof-check\nimport { UnauthorizedError } from 'payload'\nif (!req.user) throw new UnauthorizedError()\n// buildFormState's string-match catch becomes redundant and can be removed.","handlingStrategy":"try-catch","validationCode":"function isAuthenticated(user: unknown): user is { id: string } {\n  return Boolean(user)\n}\n\nif (!isAuthenticated(req.user)) {\n  // avoid the nested 'Unauthorized' string throw entirely\n  redirect('/login')\n}","typeGuard":"import { UnauthorizedError } from 'payload'\n\nfunction isUnauthorizedError(err: unknown): err is UnauthorizedError {\n  return err instanceof UnauthorizedError\n}","tryCatchPattern":"try {\n  await buildFormState({ collectionSlug, schemaPath })\n} catch (err) {\n  if (isUnauthorizedError(err)) {\n    redirectToLogin()\n    return\n  }\n  throw err\n}","preventionTips":["Throw UnauthorizedError (not a bare 'Unauthorized' string) in nested functions so callers can type-narrow.","Ensure req.user is propagated to every nested server function during form-state build.","Treat a 401 from buildFormState as a session-expiry signal and re-authenticate."],"tags":["ui","form-state","auth","unauthorized","error-wrapping"],"backgroundTag":null,"analyzedSha":"00c58b35c0ed348ddc22daabf467b139727214fd","analyzedAt":"2026-08-12T20:45:03.758Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}