HELGE SVERREAll-stack Developer
Bergen, Norwayv13.0
est. 2012  |  197 repos  |  12.8k+ contributions
Tools  |   Theme:
Fixing "folio:list is registered under multiple names" on Laravel 13
August 5, 2026

Upgraded an app to Laravel 13 and suddenly every artisan command failed:

ERROR  The "folio:list" command cannot be found because it is registered under multiple names.

Cause

laravel/folio (v1.1.19, still the latest) ships a ListCommand that extends Laravel's RouteListCommand and tries to rename it with a property:

#[AsCommand(name: 'folio:list')]
class ListCommand extends RouteListCommand
{
    protected $name = 'folio:list';

Doesn't work anymore. Laravel 13's RouteListCommand defines protected $signature = 'route:list ...', and Illuminate\Console\Command::__construct() checks $signature before $name. The child inherits the signature, so the command instantiates as route:list while Symfony's lazy command loader advertises it as folio:list. Symfony resolves it, finds nothing registered under folio:list, and throws.

Folio has no release with a fix, so override it locally.

Fix

1. A command with a proper signatureapp/Console/Commands/FolioListCommand.php:

<?php

namespace App\Console\Commands;

use Laravel\Folio\Console\ListCommand;
use Symfony\Component\Console\Attribute\AsCommand;

#[AsCommand(name: 'folio:list')]
class FolioListCommand extends ListCommand
{
    protected $signature = 'folio:list
                    {--json : Output the route list as JSON}
                    {--method= : Filter the routes by method}
                    {--action= : Filter the routes by action}
                    {--name= : Filter the routes by name}
                    {--domain= : Filter the routes by domain}
                    {--middleware= : Filter the routes by middleware}
                    {--path= : Only show routes matching the given path pattern}
                    {--except-path= : Do not display the routes matching the given path pattern}
                    {--r|reverse : Reverse the ordering of the routes}
                    {--sort=uri : The column (domain, method, uri, name, action, middleware, definition) to sort by}
                    {--except-vendor : Do not display routes defined by vendor packages}
                    {--only-vendor : Only display routes defined by vendor packages}';

    protected $name = 'folio:list';
}

2. Register it in your own app/Providers/FolioServiceProvider.php (the one folio:install published):

use App\Console\Commands\FolioListCommand;

public function boot(): void
{
    Folio::path(resource_path('views/pages'))->middleware([
        '*' => [
            //
        ],
    ]);

    if ($this->app->runningInConsole()) {
        $this->commands([FolioListCommand::class]);
    }
}

That's it. The package's broken command still gets registered, but Laravel's lazy command map is keyed by the AsCommand attribute name, and app providers boot after package providers — so your entry overwrites the package's folio:list mapping and the broken class is never resolved.

php artisan, folio:list, and route:list all work again, and everything else Folio does is untouched.




<!-- generated with nested tables and zero regrets -->