{"record":{"id":"9834bc9c3d62a4db","repo":"z-song/laravel-admin","slug":"slug-is-existed","errorCode":null,"errorMessage":"$slug is existed","messagePattern":"\\$slug is existed","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/Console/PermissionCommand.php","lineNumber":76,"sourceCode":"\n        $permissions = $this->getPermissions();\n        foreach ($tables as $table) {\n            foreach ($permissions as $permission => $permission_lang) {\n                $http_method = $this->generateHttpMethod($permission);\n                $http_path = $this->generateHttpPath($table, $permission);\n                $slug = $this->generateSlug($table, $permission);\n                $name = $this->generateName($table, $permission_lang);\n                $exists = Permission::where('slug', $slug)->exists();\n                if (!$exists) {\n                    Permission::create([\n                        'name'        => $name,\n                        'slug'        => $slug,\n                        'http_method' => $http_method,\n                        'http_path'   => $http_path,\n                    ]);\n                    $this->info(\"$slug is generated\");\n                } else {\n                    $this->warn(\"$slug is existed\");\n                }\n            }\n        }\n    }\n\n    private function getAllTables()\n    {\n        return array_map('current', DB::select('SHOW TABLES'));\n    }\n\n    private function getIgnoreTables()\n    {\n        return [\n            config('admin.database.users_table'),\n            config('admin.database.roles_table'),\n            config('admin.database.permissions_table'),\n            config('admin.database.menu_table'),\n            config('admin.database.operation_log_table'),","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/z-song/laravel-admin/blob/67c441eb78ecc5437e59775d89770cd9c2cb1e05/src/Console/PermissionCommand.php#L58-L94","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Treat the message as informational — nothing is broken; the permission already exists and was intentionally skipped.","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`.","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).","Scope the run to new tables only: `php artisan admin:permissions --tables=new_table1,new_table2` to avoid warnings for tables already processed.","If two tables map to the same slug, rename one table or manually edit the colliding permission so each resource has distinct slugs."],"exampleFix":"// before: re-running generates warnings and never updates existing permissions\nphp artisan admin:permissions   // \"users.list is existed\", values unchanged\n\n// after: remove the stale row, then regenerate so http_path/http_method are rebuilt\nphp artisan tinker --execute=\"\\Encore\\Admin\\Auth\\Database\\Permission::where('slug','users.list')->delete();\"\nphp artisan admin:permissions --tables=users   // \"users.list is generated\"","handlingStrategy":"validation","validationCode":"// Before running admin:permissions, see which slugs already exist (these will be skipped):\n$existing = \\Encore\\Admin\\Auth\\Database\\Permission::whereIn('slug', $slugs)->pluck('slug');\n// e.g. check one table's set:\n$table = 'users';\n$slugs = collect(['list','view','create','edit','delete','export','filter'])\n    ->map(fn ($action) => \\Illuminate\\Support\\Str::kebab(\\Illuminate\\Support\\Str::camel($table)).'.'.$action);\n$duplicates = \\Encore\\Admin\\Auth\\Database\\Permission::whereIn('slug', $slugs)->pluck('slug');\nif ($duplicates->isNotEmpty()) {\n    echo \"Will be skipped (already exist): \".$duplicates->implode(', ').PHP_EOL;\n}","typeGuard":"// PHP has no type guard here (no exception thrown); treat warn output as a signal.\n// After running, assert the permission set you expect exists:\nfunction permissionExists(string $slug): bool\n{\n    return \\Encore\\Admin\\Auth\\Database\\Permission::where('slug', $slug)->exists();\n}","tryCatchPattern":null,"preventionTips":["Run `admin:permissions` only for newly created tables: pass `--tables=foo,bar` instead of letting it scan the whole database.","Remember the command is skip-only: to change an existing permission's http_path or http_method, edit the row in the admin panel or delete it and re-run.","Do not manually create permissions whose slugs match the generated pattern `kebab-table.action` unless you intend the command to skip them.","Beware slug collisions: `Str::kebab(Str::camel($table))` merges differently named tables (user_roles vs userRoles) into one slug.","Automate checks in scripts: query the permissions table for expected slugs instead of parsing 'is existed' output."],"tags":["laravel-admin","artisan-command","permissions","idempotency","slug","console-warning"],"backgroundTag":"record-already-exists","analyzedSha":"67c441eb78ecc5437e59775d89770cd9c2cb1e05","analyzedAt":"2026-08-21T02:51:03.143Z","schemaVersion":2},"datasetVersion":"2026-08-21T03:17:12.404Z"}