python/cpython · error · ValueError

invalid nargs value

Error message

invalid nargs value

What it means

In HelpFormatter._format_args, after handling the sentinel nargs values ('?', '*', '+', REMAINDER, PARSER, SUPPRESS), the code builds a metavar list using range(action.nargs). If nargs is a float or other non-int (e.g. 2.0 or '2'), range() raises TypeError, which is converted to ValueError('invalid nargs value'). It means the parser was constructed with an unusable nargs.

Source

Thrown at Lib/argparse.py:711

        elif action.nargs == ZERO_OR_MORE:
            metavar = get_metavar(1)
            if len(metavar) == 2:
                result = '[%s [%s ...]]' % metavar
            else:
                result = '[%s ...]' % metavar
        elif action.nargs == ONE_OR_MORE:
            result = '%s [%s ...]' % get_metavar(2)
        elif action.nargs == REMAINDER:
            result = '...'
        elif action.nargs == PARSER:
            result = '%s ...' % get_metavar(1)
        elif action.nargs == SUPPRESS:
            result = ''
        else:
            try:
                formats = ['%s' for _ in range(action.nargs)]
            except TypeError:
                raise ValueError("invalid nargs value") from None
            result = ' '.join(formats) % get_metavar(action.nargs)
        return result

    def _expand_help(self, action):
        help_string = str(self._get_help_string(action))
        if '%' not in help_string:
            return self._apply_text_markup(help_string)
        params = dict(vars(action), prog=self._prog)
        for name in list(params):
            value = params[name]
            if value is SUPPRESS:
                del params[name]
            elif hasattr(value, '__name__'):
                params[name] = value.__name__
        if params.get('choices') is not None:
            params['choices'] = ', '.join(map(str, params['choices']))

        t = self._theme

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Pass an int or one of the documented sentinels: nargs=3, '?', '*', '+'.
  2. Coerce computed values: nargs=int(count).
  3. Validate config-sourced nargs before building the parser: allow only int or the four sentinel strings.

Example fix

# before
parser.add_argument('--pos', nargs=2.0)  # ValueError: invalid nargs value

# after
parser.add_argument('--pos', nargs=int(2.0))
Defensive patterns

Strategy: validation

Validate before calling

NARGS_SENTINELS = {'?', '*', '+'}

def valid_nargs(v) -> bool:
    return v in NARGS_SENTINELS or (isinstance(v, int) and not isinstance(v, bool) and v >= 0)

Type guard

def is_int_nargs(v) -> bool:
    return isinstance(v, int) and not isinstance(v, bool)

Prevention

When it happens

Trigger: argparse.add_argument('--x', nargs=1.5); nargs='two' (string); nargs=2.0 (float); a computed nargs like len(items)/2 that yields a float.

Common situations: Config-driven CLI builders converting YAML/JSON values where 2 parses as float; arithmetic on nargs counts producing floats; passing '*' vs '*' confusion or the string '3'.

Related errors


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