{"record":{"id":"b701c04b106cf139","repo":"payloadcms/payload","slug":"unauthorized","errorCode":null,"errorMessage":"Unauthorized","messagePattern":"Unauthorized","errorType":"http","errorClass":"APIError","httpStatus":401,"severity":"error","filePath":"packages/plugin-multi-tenant/src/endpoints/getTenantOptionsEndpoint.ts","lineNumber":26,"sourceCode":"\nexport const getTenantOptionsEndpoint = ({\n  tenantsArrayFieldName,\n  tenantsArrayTenantFieldName,\n  tenantsCollectionSlug,\n  useAsTitle,\n  userHasAccessToAllTenants,\n}: {\n  tenantsArrayFieldName: string\n  tenantsArrayTenantFieldName: string\n  tenantsCollectionSlug: string\n  useAsTitle: string\n  userHasAccessToAllTenants: Required<MultiTenantPluginConfig>['userHasAccessToAllTenants']\n}): Endpoint => ({\n  handler: async (req) => {\n    const { payload, user } = req\n\n    if (!user) {\n      throw new APIError('Unauthorized', 401)\n    }\n\n    const tenantOptions = await getTenantOptions({\n      payload,\n      tenantsArrayFieldName,\n      tenantsArrayTenantFieldName,\n      tenantsCollectionSlug,\n      useAsTitle,\n      user,\n      userHasAccessToAllTenants,\n    })\n\n    return new Response(JSON.stringify({ tenantOptions }))\n  },\n  method: 'get',\n  path: '/populate-tenant-options',\n})\n","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/payloadcms/payload/blob/00c58b35c0ed348ddc22daabf467b139727214fd/packages/plugin-multi-tenant/src/endpoints/getTenantOptionsEndpoint.ts#L8-L44","documentation":"Thrown by the multi-tenant plugin's `getTenantOptionsEndpoint` handler as a 401 when the request to `/populate-tenant-options` has no authenticated user. The endpoint exists to return the tenant list the current user can access, so an anonymous request has nothing to filter.","triggerScenarios":"Hitting the `/populate-tenant-options` GET endpoint without a session; calling it from an unauthenticated frontend before login; expired session cookie; server-to-server fetch that omits credentials.","commonSituations":"Frontend tenant selector dropdown firing before the login flow completes; cookie blocked by SameSite/secure; a public page that mistakenly mounts the tenant picker without gating on auth.","solutions":["Ensure the caller is authenticated before requesting tenant options (gate the UI on login state)","Pass the session cookie / API key with the request","If the picker must render for anonymous users, fetch tenant options only after login succeeds"],"exampleFix":"// before\nfetch('/api/tenants/populate-tenant-options')\n// after\nfetch('/api/tenants/populate-tenant-options', { credentials: 'include' })","handlingStrategy":"validation","validationCode":"// Only fetch tenant options when a user is present\nif (!currentUser) return []\nreturn await fetch('/api/tenants/populate-tenant-options', { credentials: 'include' }).then(r => r.json())","typeGuard":null,"tryCatchPattern":"const res = await fetch('/api/tenants/populate-tenant-options', { credentials: 'include' })\nif (res.status === 401) { await relogin(); return fetchOriginal() }","preventionTips":["Gate the tenant-picker UI on a logged-in user","Send `credentials: 'include'` (or an API key) on the request","Handle 401 by re-authenticating before retrying"],"tags":["multi-tenant","authentication","unauthorized","rest"],"backgroundTag":null,"analyzedSha":"00c58b35c0ed348ddc22daabf467b139727214fd","analyzedAt":"2026-08-12T20:45:03.758Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}