CLI: reject unknown tokens after a parent command with subcommands#19425
Merged
Conversation
ADmad
approved these changes
May 4, 2026
markstory
approved these changes
May 10, 2026
Previously, running e.g. `bin/cake i18n nonsense` silently invoked I18nCommand because `i18n` is a registered command, and the leftover token `nonsense` was passed through as a positional argument that the parser silently swallowed. That hid genuine typos. When the matched command also has sibling subcommands (e.g. `i18n init` and `i18n extract` exist alongside `i18n`), an unrecognized next token is almost certainly a typo for a subcommand. Reject those cases up front in CommandRunner with a message that lists the available subcommands. Commands without siblings, commands with declared positional arguments, and option-like tokens (`--help`, `-v`) are unaffected.
925cc90 to
b837960
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Previously, running e.g.
bin/cake i18n nonsensesilently invokedI18nCommandand ignored thenonsensetoken, because:i18nis a registered command (the interactiveI18nCommand).i18ndefines no positional arguments, soConsoleOptionParser::_parseArg()silently appends extras instead of rejecting them.That hid genuine typos and made it look like CakePHP accepted any garbage after a known command name.
What this changes
In
CommandRunner::run(), after the existing command-name resolution, when all of the following are true:-),<name>as a prefix),then the next token is almost certainly meant to be a subcommand. If it doesn't match a registered subcommand, error out with a clear message listing the available subcommands.
What this does NOT change
addArgument()— unchanged; the parser already validates them.RoutesGenerateCommandthat intentionally accept arbitrary positional args (bin/cake routes generate controller:Articles action:view 2) — unchanged, becauseroutes generatehas no sibling subcommands.--help,-v, etc.) following the command name — unchanged.Related
bin/cake schema_cache nonsense) by routing to filtered help with only the prefix as argv. Complementary to this PR.Alternative considered
Removing the silent-accept branch in
ConsoleOptionParser::_parseArg()to make every parser strict by default. This was implemented and tested, but it breaks commands (including core'sRoutesGenerateCommand) that intentionally accept arbitrary positional args without declaring them, and surfaces several test bugs around boolean options being passed values. That route would need a new opt-in API (e.g. a$parser->allowExtraArguments()flag) and a wider migration. Out of scope for this PR; happy to follow up if there's appetite.