- 
          
- 
                Notifications
    You must be signed in to change notification settings 
- Fork 1.8k
Description
Description
Spatie Laravel Permission - Bug Report
Summary
Memory exhaustion (134MB limit) when checking permissions that a user doesn't have via @can() Blade directive, specifically affecting users with the "applicant" role.
Environment
- Package Version: spatie/laravel-permission v6.21.0
- Laravel Version: 10.x
- PHP Version: 8.1+
- Database: MySQL/PostgreSQL
Bug Description
When a user (specifically with role "applicant") accesses a page with multiple @can() Blade directives checking permissions they DON'T have, the system runs out of memory:
PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 12288 bytes)
in /vendor/spatie/laravel-permission/src/Guard.php on line 69
Hypothesis
The Guard class appears to have an infinite loop or recursive query when:
- User has a role with limited permissions (e.g., 9 permissions)
- Multiple @can()checks are made for permissions they DON'T have
- The "permission denied" code path triggers excessive memory allocation
Possible causes:
- Circular relationship loading
- N+1 query problem in permission resolution
- Missing cache/memoization for negative permission checks
- Recursive getAllPermissions() calls
Workaround
We worked around this by bypassing Spatie's Guard for affected users and querying permissions directly:
// Direct DB query instead of Spatie's Guard
$hasPermission = DB::table('permissions as p')
    ->join('role_has_permissions as rhp', 'p.id', '=', 'rhp.permission_id')
    ->join('model_has_roles as mhr', 'rhp.role_id', '=', 'mhr.role_id')
    ->where('mhr.model_type', 'App\\Models\\User')
    ->where('mhr.model_id', $userId)
    ->where('p.name', $permissionName)
    ->exists();This works perfectly with no memory issues.
Expected Behavior
@can() checks should return false quickly for permissions user doesn't have, without memory exhaustion.
Actual Behavior
Memory exhaustion when checking multiple permissions user doesn't have.
Additional Context
Database structure:
- 55 total permissions in system
- Applicant role has 9 permissions
- Admin role has 55 permissions
- Officer role has 23 permissions
Permission IDs:
- Min ID: 109
- Max ID: 163
- Applicant permission IDs: 109, 110, 111, 112, 118, 126, 127, 131, 157
Questions for Maintainers
- Is there known caching mechanism that could cause this?
- Should we investigate the Gate/Guard resolution for negative checks?
- Would eager loading permissions prevent this issue?
- Is this related to permission ID ranges (starting at 109 vs 1)?
Willing to Contribute
I'm willing to:
- Create a failing test case
- Debug the Guard.php code to find exact issue
- Submit a PR with a fix
- Test the fix thoroughly
Please advise on next steps!
Steps To Reproduce
Reproduction Steps
1. Setup
# Create a role with limited permissions
php artisan tinker
$applicant = Role::create(['name' => 'applicant']);
$applicant->givePermissionTo(['view applications', 'create applications']);2. Create a user with this role
$user = User::create([
    'email' => '[email protected]',
    'password' => bcrypt('password'),
    'role' => 'applicant'
]);
$user->assignRole('applicant');3. Create a Blade view with multiple permission checks
{{-- resources/views/layouts/app.blade.php --}}
<nav>
    @can('view applications')
        <a href="/applications">Applications</a>
    @endcan
    @can('review applications') {{-- User DOESN'T have this --}}
        <a href="/reviews">Reviews</a>
    @endcan
    @can('view audit logs') {{-- User DOESN'T have this --}}
        <a href="/audit">Audit Logs</a>
    @endcan
    @can('view reports') {{-- User DOESN'T have this --}}
        <a href="/reports">Reports</a>
    @endcan
    {{-- Add 10+ more @can() checks for permissions user doesn't have --}}
</nav>4. Login as applicant and view the page
The page will hang and eventually crash with memory exhaustion.
Key Findings
- Works fine in Tinker:
$user = User::find(9);
$user->can('review applications'); // Returns false - no memory issue- 
Fails in web request with Blade: When the layout renders with multiple @can()directives
- 
Only affects certain users: - ✅ Admin users with MANY permissions: Works fine
- ✅ Officer users with MODERATE permissions: Works fine
- ❌ Applicant users with FEW permissions: Memory exhaustion
 
- 
Triggers on denied permissions: The bug occurs when checking permissions the user doesn't have 
Stack Trace
Allowed memory size of 134217728 bytes exhausted (tried to allocate 552960 bytes)
at vendor/laravel/framework/src/Illuminate/Database/Eloquent/Collection.php:554
Context shows the error originates from:
vendor/spatie/laravel-permission/src/Guard.php:69
### Example Application
_No response_
### Version of spatie/laravel-permission package:
spatie/laravel-permission v6.21.0
### Version of laravel/framework package:
10.x
### PHP version:
8.1+
### Database engine and version:
MySQL/PostgreSQL
### OS: Windows/Mac/Linux version:
Mac