z-song/laravel-admin · warning

$slug is existed

Error message

$slug is existed

What it means

This is not an exception but a console warning emitted by laravel-admin's `admin:permissions` command (src/Console/PermissionCommand.php:76). The command scans every database table (minus the admin system tables) and auto-generates seven CRUD permission rows per table (list, view, create, edit, delete, export, filter) with slugs like `users.list`. When `Permission::where('slug', $slug)->exists()` is true, the row is skipped and the command prints "<slug> is existed" so you know that permission was not regenerated. It is an idempotency notice: the command never overwrites existing permissions.

Source

Thrown at src/Console/PermissionCommand.php:76

        $permissions = $this->getPermissions();
        foreach ($tables as $table) {
            foreach ($permissions as $permission => $permission_lang) {
                $http_method = $this->generateHttpMethod($permission);
                $http_path = $this->generateHttpPath($table, $permission);
                $slug = $this->generateSlug($table, $permission);
                $name = $this->generateName($table, $permission_lang);
                $exists = Permission::where('slug', $slug)->exists();
                if (!$exists) {
                    Permission::create([
                        'name'        => $name,
                        'slug'        => $slug,
                        'http_method' => $http_method,
                        'http_path'   => $http_path,
                    ]);
                    $this->info("$slug is generated");
                } else {
                    $this->warn("$slug is existed");
                }
            }
        }
    }

    private function getAllTables()
    {
        return array_map('current', DB::select('SHOW TABLES'));
    }

    private function getIgnoreTables()
    {
        return [
            config('admin.database.users_table'),
            config('admin.database.roles_table'),
            config('admin.database.permissions_table'),
            config('admin.database.menu_table'),
            config('admin.database.operation_log_table'),

View on GitHub (pinned to 67c441eb78)

Solutions

  1. Treat the message as informational — nothing is broken; the permission already exists and was intentionally skipped.
  2. If you want the command to regenerate a permission, delete or rename the existing row first (in the admin panel under Authority > Permission, or `DB::table(config('admin.database.permissions_table'))->where('slug', $slug)->delete()`), then re-run `php artisan admin:permissions`.
  3. To regenerate everything, truncate the permissions + role_permissions + user_permissions pivot tables and re-run the command (only in a safe environment; role assignments will be lost).
  4. Scope the run to new tables only: `php artisan admin:permissions --tables=new_table1,new_table2` to avoid warnings for tables already processed.
  5. If two tables map to the same slug, rename one table or manually edit the colliding permission so each resource has distinct slugs.

Example fix

// before: re-running generates warnings and never updates existing permissions
php artisan admin:permissions   // "users.list is existed", values unchanged

// after: remove the stale row, then regenerate so http_path/http_method are rebuilt
php artisan tinker --execute="\Encore\Admin\Auth\Database\Permission::where('slug','users.list')->delete();"
php artisan admin:permissions --tables=users   // "users.list is generated"
Defensive patterns

Strategy: validation

Validate before calling

// Before running admin:permissions, see which slugs already exist (these will be skipped):
$existing = \Encore\Admin\Auth\Database\Permission::whereIn('slug', $slugs)->pluck('slug');
// e.g. check one table's set:
$table = 'users';
$slugs = collect(['list','view','create','edit','delete','export','filter'])
    ->map(fn ($action) => \Illuminate\Support\Str::kebab(\Illuminate\Support\Str::camel($table)).'.'.$action);
$duplicates = \Encore\Admin\Auth\Database\Permission::whereIn('slug', $slugs)->pluck('slug');
if ($duplicates->isNotEmpty()) {
    echo "Will be skipped (already exist): ".$duplicates->implode(', ').PHP_EOL;
}

Type guard

// PHP has no type guard here (no exception thrown); treat warn output as a signal.
// After running, assert the permission set you expect exists:
function permissionExists(string $slug): bool
{
    return \Encore\Admin\Auth\Database\Permission::where('slug', $slug)->exists();
}

Prevention

When it happens

Trigger: Running `php artisan admin:permissions` a second time after a successful first run (every slug now exists). Running it after `admin:install` already seeded permissions, or after you created matching permissions manually in the admin panel (slug `resource.action`). Two different table names that collapse to the same kebab slug (e.g. `user_roles` and `userRoles` both produce `user-roles.list`). Specifying `--tables=` with tables whose permissions were already generated.

Common situations: Re-running the command hoping to refresh permissions after adding new columns or renaming tables (it will not update existing rows — only skip them). Environments where permissions were customized via the admin UI and the developer expects the command to overwrite them. Multi-developer teams where one member seeded permissions and another re-runs the generator. Copying a database between environments (permissions already present) and then running the generator.


AI-assisted analysis of z-song/laravel-admin@67c441eb78 (2026-08-21). Data as JSON: /api/errors/9834bc9c3d62a4db. Report an issue: GitHub.