python/cpython · error · ArgumentError
invalid choice: %(value)r, maybe you meant %(closest)r? (cho
Error message
invalid choice: %(value)r, maybe you meant %(closest)r? (choose from %(choices)s)
What it means
Same invalid-choice check as the plain error, but when the parser was constructed with suggest_on_error=True (new in Python 3.14) and both the value and all choices are strings, argparse runs difflib.get_close_matches and, if a nearest candidate within the cutoff exists, embeds it in the message as 'maybe you meant ...?'. The raise site is identical to the non-suggesting variant in _check_value.
Source
Thrown at Lib/argparse.py:2838
return
if isinstance(choices, str):
choices = iter(choices)
if value not in choices:
args = {'value': str(value),
'choices': ', '.join(repr(str(choice)) for choice in action.choices)}
msg = _('invalid choice: %(value)r (choose from %(choices)s)')
if self.suggest_on_error and isinstance(value, str):
if all(isinstance(choice, str) for choice in action.choices):
suggestions = difflib.get_close_matches(value, action.choices, 1)
if suggestions:
args['closest'] = suggestions[0]
msg = _('invalid choice: %(value)r, maybe you meant %(closest)r? '
'(choose from %(choices)s)')
raise ArgumentError(action, msg % args)
# =======================
# Help-formatting methods
# =======================
def format_usage(self, formatter=None):
if formatter is None:
formatter = self._get_formatter()
formatter.add_usage(self.usage, self._actions,
self._mutually_exclusive_groups)
return formatter.format_help()
def format_help(self, formatter=None):
if formatter is None:
formatter = self._get_formatter()
# usage
formatter.add_usage(self.usage, self._actions,View on GitHub (pinned to bc6749cc3b)
Solutions
- Use the suggested choice from the message.
- Keep suggest_on_error off (default) if your test suite asserts exact error text.
- Normalize case/whitespace via type=str.lower/.strip so near-misses collapse to exact matches.
Example fix
# before
parser = argparse.ArgumentParser(suggest_on_error=True)
parser.add_argument('--fmt', choices=['json', 'xml'])
parser.parse_args(['--fmt', 'jsn'])
# invalid choice: 'jsn', maybe you meant 'json'? (choose from 'json', 'xml')
# after
parser.parse_args(['--fmt', 'json']) Defensive patterns
Strategy: validation
Validate before calling
def suggest(parser, value, allowed):
import difflib
m = difflib.get_close_matches(value, [str(c) for c in allowed], 1)
return m[0] if m else None
# pre-validate and hint before argparse raises
hint = suggest(parser, raw_value, choices_list) Try / catch
try:
args = parser.parse_args(argv)
except argparse.ArgumentError as e:
if 'invalid choice' in str(e):
print('check the printed choices list; the message may include a suggestion') Prevention
- Keep suggest_on_error off in CI/tests that assert exact error strings.
- Normalize input (case/whitespace) so suggestions rarely matter.
- When you enable suggestions, update user-facing docs to describe the extended message.
When it happens
Trigger: ArgumentParser(suggest_on_error=True) plus add_argument(x, choices=[...strings...]); the user supplies a string within difflib's similarity cutoff of exactly one choice (e.g. 'jsn' for 'json'). Non-string choices or suggest_on_error=False always yield the plain message.
Common situations: Human-facing CLIs where typos are common (--colour vs --color style near-misses); enabling the flag to improve UX and then seeing the extended message in captured error output; tests asserting the exact error string breaking after the flag is turned on.
Related errors
- invalid choice: %(value)r (choose from %(choices)s)
- invalid nargs value
- .__call__() not defined
- invalid option name {option_string!r} for BooleanOptionalAct
- nargs for store actions must be != 0; if you have nothing to
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/74913caedc5d2431.
Report an issue: GitHub.