RustPython/RustPython · error · ValueError

unknown action {action_class!r}

Error message

unknown action {action_class!r}

What it means

add_argument resolves action= through the parser's 'action' registry (built-ins such as 'store', 'store_true', 'append', plus entries added with parser.register('action', ...)). If the resolved value is not callable — a typo'd string, an unregistered name, or an Action instance instead of the class — this ValueError is raised before the action is constructed.

Source

Thrown at Lib/argparse.py:1538

            kwargs = self._get_positional_kwargs(*args, **kwargs)

        # otherwise, we're adding an optional argument
        else:
            kwargs = self._get_optional_kwargs(*args, **kwargs)

        # if no default was supplied, use the parser-level default
        if 'default' not in kwargs:
            dest = kwargs['dest']
            if dest in self._defaults:
                kwargs['default'] = self._defaults[dest]
            elif self.argument_default is not None:
                kwargs['default'] = self.argument_default

        # create the action object, and add it to the parser
        action_name = kwargs.get('action')
        action_class = self._pop_action_class(kwargs)
        if not callable(action_class):
            raise ValueError(f'unknown action {action_class!r}')
        action = action_class(**kwargs)

        # raise an error if action for positional argument does not
        # consume arguments
        if not action.option_strings and action.nargs == 0:
            raise ValueError(f'action {action_name!r} is not valid for positional arguments')

        # raise an error if the action type is not callable
        type_func = self._registry_get('type', action.type, action.type)
        if not callable(type_func):
            raise TypeError(f'{type_func!r} is not callable')

        if type_func is FileType:
            raise TypeError(f'{type_func!r} is a FileType class object, '
                            f'instance of it must be passed')

        # raise an error if the metavar does not match the type
        if hasattr(self, "_get_validation_formatter"):

View on GitHub (pinned to aaeab4f754)

Solutions

  1. Use a registered built-in name exactly: store, store_const, store_true, store_false, append, append_const, count, help, version, extend.
  2. Pass the class object itself: action=MyAction, and for the boolean pair use action=argparse.BooleanOptionalAction (the class).
  3. For string-based dispatch, register first: parser.register('action', 'mine', MyAction).

Example fix

# before
parser.add_argument('-v', action='strore_true')
# after
parser.add_argument('-v', action='store_true')
Defensive patterns

Strategy: type-guard

Validate before calling

BUILTIN_ACTIONS = {'store', 'store_const', 'store_true', 'store_false', 'append', 'append_const', 'count', 'help', 'version', 'extend'}
def valid_action(value):
    return callable(value) or value in BUILTIN_ACTIONS
assert valid_action(action_value), 'unknown action ' + repr(action_value)

Type guard

def is_action_spec(value) -> bool:
    return callable(value) or (isinstance(value, str) and value in BUILTIN_ACTIONS)

Prevention

When it happens

Trigger: action='strore' (misspelled); action='mine' without prior parser.register('action', 'mine', MyAction); passing an Action instance, which has no __call__, instead of the class.

Common situations: Typos in action names; custom action classes referenced by string before registration; config-driven CLI builders passing unvalidated strings.

Related errors


AI-assisted analysis of RustPython/RustPython@aaeab4f754 (2026-08-17). Data as JSON: /api/errors/c6245e1ea89eb1f9. Report an issue: GitHub.