plugin-multi-tenant: `isGlobal` collections redirect tenant-scoped users to `/admin` since 3.93.0 (GlobalViewRedirect prop-name mismatch)
Maintainers usually reply within 1 day
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 76/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- next.js, typescript
- Domain
- backend, backend-api-design
Research direction
Read packages/plugin-multi-tenant/src/index.ts and packages/plugin-multi-tenant/src/components/GlobalViewRedirect/index.ts to compare the registered server prop names with the component’s arguments. Reproduce with the linked repro using a tenant-scoped user who cannot access all tenants. Done when that user opening an isGlobal collection reaches its tenant’s document instead of /admin.
Written by the indexing model from the issue text.
Description
Describe the Bug
Since 3.93.0, a user who has access to some tenants (but not all tenants) can't open an isGlobal: true collection. The list view, a direct document URL and the dashboard card all load and then bounce to /admin. Users for whom userHasAccessToAllTenants returns true are not affected.
The cause is a prop-name mismatch between the plugin's registration of GlobalViewRedirect and the component.
packages/plugin-multi-tenant/src/index.ts registers it with tenantsArrayFieldName / tenantsArrayTenantFieldName:
{
path: '@payloadcms/plugin-multi-tenant/rsc#GlobalViewRedirect',
serverProps: {
globalSlugs: globalCollectionSlugs,
tenantFieldName,
tenantsArrayFieldName,
tenantsArrayTenantFieldName,
tenantsCollectionSlug,
useAsTitle: tenantCollection.admin?.useAsTitle || 'id',
userHasAccessToAllTenants,
},
}
packages/plugin-multi-tenant/src/components/GlobalViewRedirect/index.ts reads tenantArrayFieldName / tenantArrayTenantFieldName (no "s"), so both values arrive as undefined:
type Args = {
// ...
tenantArrayFieldName: string
tenantArrayTenantFieldName: string
// ...
}
const redirectRoute = await getGlobalViewRedirect({
// ...
tenantsArrayFieldName: args.tenantArrayFieldName,
tenantsArrayTenantFieldName: args.tenantArrayTenantFieldName,
// ...
})
The mismatch is older than 3.93.0, but it rarely mattered before then. Up to 3.92.x, getGlobalViewRedirect used the payload-tenant cookie and only called getTenantOptions when that cookie was missing. Commit 43c32b194 ("fix: constrain global view redirects to available tenants", shipped in 3.93.0) now calls getTenantOptions on every request. For a user without all-tenants access, getTenantOptions reads user[undefined], finds no tenants, and the helper falls through to its "no tenants were found" branch, which redirects to the admin root.
The same mismatch is on main (v4).
Link to the code that reproduces this issue
https://github.com/jmtorres/payload-multi-tenant-global-redirect
Reproduction Steps
- Clone the repro (it uses the
blanktemplate on SQLite with Payload 3.93.0), then runcp .env.example .env,pnpm install,pnpm payload run src/seed.tsandpnpm dev.- Plugin config:
collections: { settings: { isGlobal: true } },userHasAccessToAllTenants: (user) => user.roles.includes('super-admin'). - The seed creates tenants A and B,
[email protected](super-admin),[email protected](roleuser, tenant A only) and onesettingsdoc for tenant A. All passwords aretest.
- Plugin config:
- Log in at
/adminas[email protected]/test. - Open Settings (
/admin/collections/settings).
Expected: a redirect to tenant A's settings doc (/admin/collections/settings/1).
Actual: the page loads, then the browser lands on /admin (the dashboard).
Logging in as [email protected] lands on /admin/collections/settings/1 as expected.
Starting the app with WORKAROUND=1 pnpm dev adds the misspelled names (tenantArrayFieldName: 'tenants', tenantArrayTenantFieldName: 'tenant') to the registered serverProps (see src/payload.config.ts). The editor then lands on the doc, which confirms the cause.
Suggested fix: rename the component's props to tenantsArrayFieldName / tenantsArrayTenantFieldName to match the registration. PR incoming.
Which area(s) are affected?
plugin: multi-tenant
Environment Info
payload: 3.93.0
@payloadcms/plugin-multi-tenant: 3.93.0
@payloadcms/db-sqlite: 3.93.0
next: 16.3.3
react: 19.2.6
Node: 24.22.2
pnpm: 12.16.1
OS: macOS (darwin arm64)
Also present on main @ e71e91c66.
- Dominant language
- TypeScript
- Stars
- 45.6k
- Forks
- 4.4k
- Avg merge
- 1d 23h
- Merged PRs (30d)
- 237
Getting set up
Starts the project's dev container in your browser, under your own GitHub account.
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from payloadcms/payload
-
area: ui Bug created-by: Contributor status: needs-triage v3
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
payloadcms/payload#19413 ·
Maintainers usually reply within 1 day
-
area: ui Bug created-by: Contributor status: needs-triage v3
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
payloadcms/payload#19412 ·
Maintainers usually reply within 1 day
-
area: ui Bug created-by: Contributor status: needs-triage v3
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
payloadcms/payload#19403 ·
Maintainers usually reply within 1 day
-
area: ui Bug created-by: Contributor status: needs-triage v3
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
payloadcms/payload#19396 ·
Maintainers usually reply within 1 day
-
area: ui Bug created-by: Contributor status: needs-triage v3
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
payloadcms/payload#19395 ·
Maintainers usually reply within 1 day
All issues in payloadcms/payload
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
Maintainers usually reply within 1 day
-
documentation easy good first issue help wanted
Difficulty 1/5 1-3 hours Newbie friendliness 83/100
Maintainers usually reply within 1 day
-
Billion-context documentation addendum: nudge is independent of window occupancy. | billion-context 文档补充:nudge 与窗口占用无关Possibly taken A pull request linked to this issue is open or already merged. Open
Difficulty 1/5 1-3 hours Newbie friendliness 86/100
ranxianglei/billion-context#5893 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 79/100
microsoft/monaco-editor#5575 ·
Maintainers usually reply within 1 day
-
enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 68/100