{"record":{"id":"3997e2464cc82f97","repo":"getgrav/grav","slug":"the-command-s-does-not-exist","errorCode":null,"errorMessage":"The command \"%s\" does not exist.","messagePattern":"The command \"(.+?)\" does not exist\\.","errorType":"console","errorClass":"CommandNotFoundException","httpStatus":null,"severity":"error","filePath":"system/src/Grav/Console/Application/CommandLoader/PluginCommandLoader.php","lineNumber":81,"sourceCode":"                    if (isset($aliases)) {\n                        foreach ($aliases as $alias) {\n                            $this->commands[$alias] = $command;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * @param string $name\n     * @return Command\n     */\n    public function get($name): Command\n    {\n        $command = $this->commands[$name] ?? null;\n        if (null === $command) {\n            throw new CommandNotFoundException(sprintf('The command \"%s\" does not exist.', $name));\n        }\n\n        return $command;\n    }\n\n    /**\n     * @param string $name\n     * @return bool\n     */\n    public function has($name): bool\n    {\n        return isset($this->commands[$name]);\n    }\n\n    /**\n     * @return string[]\n     */\n    public function getNames(): array","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/getgrav/grav/blob/6040efed04efa69b8209448ed81308e7c24147c2/system/src/Grav/Console/Application/CommandLoader/PluginCommandLoader.php#L63-L99","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["List what the loader actually registered: run `bin/plugin <plugin> list` (or call getNames() on the loader) and use the exact command name shown.","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.","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.","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."],"exampleFix":"// file user/plugins/myplugin/cli/DoThingCommand.php\n// before: class DoStuff extends Command { ... }  // wrong class name -> never loaded\nclass DoThingCommand extends Command {\n    protected function configure(): void\n    {\n        $this->setName('do-thing');\n    }\n}\n// after: `bin/plugin myplugin do-thing` now resolves via PluginCommandLoader","handlingStrategy":"validation","validationCode":"// before calling get()\n$names = $loader->getNames();\nif (!$loader->has($commandName)) {\n    fwrite(STDERR, \"Unknown command. Available: \" . implode(', ', $names) . PHP_EOL);\n    exit(1);\n}\n$command = $loader->get($commandName);","typeGuard":null,"tryCatchPattern":"try {\n    $command = $loader->get($name);\n} catch (\\Symfony\\Component\\Console\\Exception\\CommandNotFoundException $e) {\n    // degrade gracefully: list available commands\n    $output->writeln('<error>' . $e->getMessage() . '</error>');\n    $output->writeln('Available: ' . implode(', ', $loader->getNames()));\n    return Command::FAILURE;\n}","preventionTips":["Always gate PluginCommandLoader::get() with has($name).","Derive command names from getName() at runtime instead of hardcoding strings.","Follow the [A-Z]\\w+Command.php + Grav\\Plugin\\Console namespace convention in every plugin's cli/ folder."],"tags":["grav","cli","console","plugin-commands","command-not-found"],"backgroundTag":"command-not-found","analyzedSha":"6040efed04efa69b8209448ed81308e7c24147c2","analyzedAt":"2026-08-17T05:07:31.593Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}