getgrav/grav · error · CommandNotFoundException

The command "%s" does not exist.

Error message

The command "%s" does not exist.

What it means

Thrown by Grav's PluginCommandLoader::get() when a command name is requested that the loader never registered. The loader discovers plugin CLI commands by scanning plugins://<name>/cli/ for files matching [A-Z]\w+Command.php whose class lives in the Grav\Plugin\Console namespace and extends Symfony\Component\Console\Command; only each command's getName() value and its aliases become addressable names. Requesting anything else raises this CommandNotFoundException.

Source

Thrown at system/src/Grav/Console/Application/CommandLoader/PluginCommandLoader.php:81

                    if (isset($aliases)) {
                        foreach ($aliases as $alias) {
                            $this->commands[$alias] = $command;
                        }
                    }
                }
            }
        }
    }

    /**
     * @param string $name
     * @return Command
     */
    public function get($name): Command
    {
        $command = $this->commands[$name] ?? null;
        if (null === $command) {
            throw new CommandNotFoundException(sprintf('The command "%s" does not exist.', $name));
        }

        return $command;
    }

    /**
     * @param string $name
     * @return bool
     */
    public function has($name): bool
    {
        return isset($this->commands[$name]);
    }

    /**
     * @return string[]
     */
    public function getNames(): array

View on GitHub (pinned to 6040efed04)

Solutions

  1. List what the loader actually registered: run `bin/plugin <plugin> list` (or call getNames() on the loader) and use the exact command name shown.
  2. Check the command file: it must live in user/plugins/<plugin>/cli/, match [A-Z]\w+Command.php, contain class Grav\Plugin\Console\<FileNameWithoutDotPhp>, and extend Symfony\Component\Console\Command.
  3. Verify the registered name: inspect the command's configure() — the name passed to setName() (or the default derived name) is what you must type; register aliases via setAliases() if you need alternate spellings.
  4. If the plugin ships no cli/ folder, the plugin exposes no CLI commands — nothing to invoke; check the plugin's docs for its actual console entry point.

Example fix

// file user/plugins/myplugin/cli/DoThingCommand.php
// before: class DoStuff extends Command { ... }  // wrong class name -> never loaded
class DoThingCommand extends Command {
    protected function configure(): void
    {
        $this->setName('do-thing');
    }
}
// after: `bin/plugin myplugin do-thing` now resolves via PluginCommandLoader
Defensive patterns

Strategy: validation

Validate before calling

// before calling get()
$names = $loader->getNames();
if (!$loader->has($commandName)) {
    fwrite(STDERR, "Unknown command. Available: " . implode(', ', $names) . PHP_EOL);
    exit(1);
}
$command = $loader->get($commandName);

Try / catch

try {
    $command = $loader->get($name);
} catch (\Symfony\Component\Console\Exception\CommandNotFoundException $e) {
    // degrade gracefully: list available commands
    $output->writeln('<error>' . $e->getMessage() . '</error>');
    $output->writeln('Available: ' . implode(', ', $loader->getNames()));
    return Command::FAILURE;
}

Prevention

When it happens

Trigger: Running `bin/plugin <plugin> <command>` where <command> is not the name returned by the command class's getName() (e.g. the file is ClearCacheCommand.php but getName() returns 'clear-cache' and you type 'clearcache'); the plugin has no cli/ subfolder at all; the PHP file/class namespace is wrong (not Grav\Plugin\Console\<Filename>), so class_exists() fails and nothing is registered; or using an alias that the command never declared.

Common situations: Typo in the command name on the CLI; plugin upgraded and a command was renamed or removed; command file naming convention violated (lowercase first letter, missing 'Command' suffix); command class in the wrong namespace after a copy-paste from another plugin; invoking `bin/plugin <plugin> list` expecting a command that the plugin simply does not ship.

Related errors


AI-assisted analysis of getgrav/grav@6040efed04 (2026-08-17). Data as JSON: /api/errors/3997e2464cc82f97. Report an issue: GitHub.