Summary
The v3 Spatie integration docs for spatie/laravel-permission recommend setting a tenant-specific PermissionRegistrar::$cacheKey on TenancyBootstrapped and resetting it on TenancyEnded:
https://tenancyforlaravel.com/docs/v3/integrations/spatie/#laravel-permission
That separates persistent cache keys, but it does not clear Spatie's already-loaded in-memory permission collection. In long-running PHP processes such as queue workers, Octane, Vapor queue lambdas, or tenant loops, PermissionRegistrar::loadPermissions() returns early when $this->permissions is already loaded, before reading from the current cacheKey.
As a result, a process can switch from tenant A to tenant B, update the cache key correctly, but still resolve permissions from tenant A's in-memory collection.
Suggested docs update
Call clearPermissionsCollection() after changing the registrar cache key, both when bootstrapping tenancy and when ending tenancy:
Events\TenancyBootstrapped::class => [
function (Events\TenancyBootstrapped $event) {
$permissionRegistrar = app(\Spatie\Permission\PermissionRegistrar::class);
$permissionRegistrar->cacheKey = 'spatie.permission.cache.tenant.'
. $event->tenancy->tenant->getTenantKey();
$permissionRegistrar->clearPermissionsCollection();
},
],
Events\TenancyEnded::class => [
function (Events\TenancyEnded $event) {
$permissionRegistrar = app(\Spatie\Permission\PermissionRegistrar::class);
$permissionRegistrar->cacheKey = 'spatie.permission.cache';
$permissionRegistrar->clearPermissionsCollection();
},
],
For the bootstrapper example, the same call should be added after setting the tenant cache key in bootstrap() and after resetting the central cache key in revert().
This keeps the persistent per-tenant cache intact, but prevents warm processes from reusing another tenant's already-hydrated permission models.
Summary
The v3 Spatie integration docs for
spatie/laravel-permissionrecommend setting a tenant-specificPermissionRegistrar::$cacheKeyonTenancyBootstrappedand resetting it onTenancyEnded:https://tenancyforlaravel.com/docs/v3/integrations/spatie/#laravel-permission
That separates persistent cache keys, but it does not clear Spatie's already-loaded in-memory permission collection. In long-running PHP processes such as queue workers, Octane, Vapor queue lambdas, or tenant loops,
PermissionRegistrar::loadPermissions()returns early when$this->permissionsis already loaded, before reading from the currentcacheKey.As a result, a process can switch from tenant A to tenant B, update the cache key correctly, but still resolve permissions from tenant A's in-memory collection.
Suggested docs update
Call
clearPermissionsCollection()after changing the registrar cache key, both when bootstrapping tenancy and when ending tenancy:For the bootstrapper example, the same call should be added after setting the tenant cache key in
bootstrap()and after resetting the central cache key inrevert().This keeps the persistent per-tenant cache intact, but prevents warm processes from reusing another tenant's already-hydrated permission models.