The Problem

Yesterday I was working on a ACL Implementation and I was using the Spatie/Permissions library all was ok, until I had to run a clean migration to test all my factories.

I was getting the following error:

  1. Spatie\Permission\Exceptions\PermissionAlreadyExists : A `view backend` permission already exists for guard `web`.

I was confused the Permissions table was empty, I was forcing to clear the permission cache file just before starting to add new permissions.

  1. // Reset cached roles and permissions
  2. app()['cache']->forget('spatie.permission.cache');

I even ran my custom composer clear-all command to clear all the cache from views/routes/permission etc.

  1. > @php artisan clear-compiled
  2. Compiled services and packages files removed!
  3. > @php artisan cache:clear
  4. Application cache cleared!
  5. > @php artisan route:clear
  6. Route cache cleared!
  7. > @php artisan view:clear
  8. Compiled views cleared!
  9. > @php artisan config:clear
  10. Configuration cache cleared!
  11. > @php artisan permission:cache-reset
  12. Permission cache flushed.
  13. > composer dumpautoload -o
  14. Generating optimized autoload files> Illuminate\Foundation\ComposerScripts::postAutoloadDump
  15. > @php artisan ide-helper:generate
  16. A new helper file was written to _ide_helper.php
  17. > @php artisan ide-helper:meta
  18. A new meta file was written to .phpstorm.meta.php
  19. > @php artisan package:discover --ansi
  20. Discovered Package: arcanedev/log-viewer
  21. Discovered Package: arcanedev/no-captcha
  22. Discovered Package: barryvdh/laravel-debugbar
  23. Discovered Package: barryvdh/laravel-ide-helper
  24. Discovered Package: beyondcode/laravel-dump-server
  25. Discovered Package: creativeorange/gravatar
  26. Discovered Package: davejamesmiller/laravel-breadcrumbs
  27. Discovered Package: fideloper/proxy
  28. Discovered Package: hieu-le/active
  29. Discovered Package: ivaano/laravel-code-generator
  30. Discovered Package: laravel/tinker
  31. Discovered Package: nesbot/carbon
  32. Discovered Package: nunomaduro/collision
  33. Discovered Package: spatie/laravel-html
  34. Discovered Package: spatie/laravel-permission
  35. Discovered Package: webpatser/laravel-uuid
  36. Package manifest generated successfully.
  37. Generated optimized autoload files containing 4595 classes

But the error kept showing every time i tried to seed, It worked if I changed the permission name or created a new permissions, but it didnt worked with the view backend permission. I spent about an hour looking into this, this happened on my linux laptop I didnt have this issue on OSX, so I left that until Today, so Today I was looking at the permissions library and didnt found anything weird, that was until I’ve decided to see what permissions where being returned, this is the method from the Permissions library

  1. /**
  2. * Get the permissions based on the passed params.
  3. *
  4. * @param array $params
  5. *
  6. * @return \Illuminate\Support\Collection
  7. */
  8. public function getPermissions(array $params = []): Collection
  9. {
  10. if ($this->permissions === null) {
  11. $this->permissions = $this->cache->remember(self::$cacheKey, self::$cacheExpirationTime, function () {
  12. return $this->getPermissionClass()
  13. ->with('roles')
  14. ->get();
  15. });
  16. }
  17. $permissions = clone $this->permissions;
  18. foreach ($params as $attr => $value) {
  19. $permissions = $permissions->where($attr, $value);
  20. }
  21. return $permissions;
  22. }

So I found that the cache was returning the view backend permission even though I have cleared the cache, so I dig a little more and found the file that was being called by the cacheManager class, and it was there and it did in fact had the view backedn key, so the command php artisan permission:cache-reset was not clearing the cache also calling it from the code was failing app()['cache']->forget('spatie.permission.cache');. (It was expected as the command is just a wrapper for this call)

In the end the problem was the file ownership, the cache was created by the apache user www-data, on OSX I didnt have this issue because I’m running apache with the same user I’m logged in.

The Solution

A quick solution would be to just remove the file manually, but I will have to find the file and remove it manually everytime I need to clear the cache, so the next approach would be to make apache run as the user I’m logged just like my OSX approach, this would also have other benefits in my dev machine, as I wont have to worry about files created by apache that I cant manage from the cli with my user.

Running apache as a different user is pretty simple in ubuntu just change the user:group in the file /etc/apache2/envvars, restart apache and change all the files to the user that will be running apache.

Lessons learned

Silent Failing is always bad, If I dont see an error where I’m expecting certain behavior I will assume the problem is somewhere else, so it will be a waste of time trying to find the error. This is a Library problem, laravel is returning false when the delete method is called /laravel/framework/src/Illuminate/Filesystem/Filesystem.php, but the library is just assuming that there will be no problems when the cache is cleared.

The fix is simple, just return the result from the cache call and if it fails at least print an error, I’ve sent a PR Show error when cache:reset command fails to fix this, hopefully it gets accepted.