python/cpython · error · ArgumentError

unknown parser %(parser_name)r (choices: %(choices)s)

Error message

unknown parser %(parser_name)r (choices: %(choices)s)

What it means

_SubParsersAction.__call__ looks up the requested subcommand name in _name_parser_map; a miss raises ArgumentError('unknown parser ...') listing the valid choices. It means the first positional word after the subparsers group does not match any name added via add_subparsers().add_parser(...) (including any aliases).

Source

Thrown at Lib/argparse.py:1436

    def _get_subactions(self):
        return self._choices_actions

    def __call__(self, parser, namespace, values, option_string=None):
        parser_name = values[0]
        arg_strings = values[1:]

        # set the parser name if requested
        if self.dest is not SUPPRESS:
            setattr(namespace, self.dest, parser_name)

        # select the parser
        try:
            subparser = self._name_parser_map[parser_name]
        except KeyError:
            args = {'parser_name': parser_name,
                    'choices': ', '.join(self._name_parser_map)}
            msg = _('unknown parser %(parser_name)r (choices: %(choices)s)') % args
            raise ArgumentError(self, msg)

        if parser_name in self._deprecated:
            parser._warning(_("command '%(parser_name)s' is deprecated") %
                            {'parser_name': parser_name})

        # parse all the remaining options into the namespace
        # store any unrecognized options on the object, so that the top
        # level parser can decide what to do with them

        # In case this subparser defines new defaults, we parse them
        # in a new namespace object and then update the original
        # namespace for the relevant parts.
        subnamespace, arg_strings = subparser.parse_known_args(arg_strings, None)
        for key, value in vars(subnamespace).items():
            setattr(namespace, key, value)

        if arg_strings:
            if not hasattr(namespace, _UNRECOGNIZED_ARGS_ATTR):

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Check the list in the error message and re-run with a registered name (or its alias).
  2. Register the missing command with subparsers.add_parser('name').
  3. Add aliases for renamed commands: add_parser('build', aliases=['b']) so old invocations keep working.

Example fix

# before
sub = parser.add_subparsers()
sub.add_parser('build')
parser.parse_args(['buld'])  # ArgumentError: unknown parser 'buld' (choices: build)

# after
sub.add_parser('build', aliases=['b'])
parser.parse_args(['b'])  # ok
Defensive patterns

Strategy: try-catch

Validate before calling

def known_subcommand(parser, name: str) -> bool:
    sub = next(a for a in parser._subparsers._group_actions)
    return name in sub._name_parser_map

Try / catch

from argparse import ArgumentError

try:
    args = parser.parse_args(argv)
except (ArgumentError, SystemExit):
    # print valid choices and re-raise with context
    valid = ', '.join(sub._name_parser_map)
    raise SystemExit(f'unknown command; choose one of: {valid}')

Prevention

When it happens

Trigger: Running `mytool buld` when only 'build' was registered; dispatching user-typed commands through a subparser; forgetting to register a newly added command; case mismatch (Build vs build); choices generated dynamically and out of sync.

Common situations: Typos in CLI invocations; plugin-based CLIs where a plugin failed to register; renaming commands without updating docs/scripts; shells auto-completing stale names.

Related errors


AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14). Data as JSON: /api/errors/937cd6e24f623da1. Report an issue: GitHub.