payloadcms/payload · error · APIError
Unauthorized
Error message
Unauthorized
What it means
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.
Source
Thrown at packages/plugin-multi-tenant/src/endpoints/getTenantOptionsEndpoint.ts:26
export const getTenantOptionsEndpoint = ({
tenantsArrayFieldName,
tenantsArrayTenantFieldName,
tenantsCollectionSlug,
useAsTitle,
userHasAccessToAllTenants,
}: {
tenantsArrayFieldName: string
tenantsArrayTenantFieldName: string
tenantsCollectionSlug: string
useAsTitle: string
userHasAccessToAllTenants: Required<MultiTenantPluginConfig>['userHasAccessToAllTenants']
}): Endpoint => ({
handler: async (req) => {
const { payload, user } = req
if (!user) {
throw new APIError('Unauthorized', 401)
}
const tenantOptions = await getTenantOptions({
payload,
tenantsArrayFieldName,
tenantsArrayTenantFieldName,
tenantsCollectionSlug,
useAsTitle,
user,
userHasAccessToAllTenants,
})
return new Response(JSON.stringify({ tenantOptions }))
},
method: 'get',
path: '/populate-tenant-options',
})
View on GitHub (pinned to 00c58b35c0)
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
Example fix
// before
fetch('/api/tenants/populate-tenant-options')
// after
fetch('/api/tenants/populate-tenant-options', { credentials: 'include' }) Defensive patterns
Strategy: validation
Validate before calling
// Only fetch tenant options when a user is present
if (!currentUser) return []
return await fetch('/api/tenants/populate-tenant-options', { credentials: 'include' }).then(r => r.json()) Try / catch
const res = await fetch('/api/tenants/populate-tenant-options', { credentials: 'include' })
if (res.status === 401) { await relogin(); return fetchOriginal() } Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- You are not allowed to perform this action.
- You are not allowed to perform this action.
- Unauthorized, you must be logged in to make this request.
- Unauthorized, you must be logged in to make this request.
- You are not allowed to perform this action.
AI-assisted analysis of payloadcms/payload@00c58b35c0 (2026-08-12).
Data as JSON: /api/errors/b701c04b106cf139.
Report an issue: GitHub.