A positional '*' gets some special handling. Its nargs is satisfied with an empty list (nothing). It's always handled. What does it mean to check an empty list of strings against the choices?
So the get_values() method does:
# when nargs='*' on a positional, if there were no command-line
# args, use the default if it is anything other than None
elif (not arg_strings and action.nargs == ZERO_OR_MORE and
not action.option_strings):
if action.default is not None:
value = action.default
else:
value = arg_strings
self._check_value(action, value)
where _check_value tests if value is in the choices.
Such a positional is best used with a valid default.
In [729]: p=argparse.ArgumentParser()
In [730]: a=p.add_argument("FLAGS", nargs='*', choices=["X","Y","Z","ALL"])
In [731]: p.parse_args([])
usage: ipython3 [-h] [{X,Y,Z,ALL} [{X,Y,Z,ALL} ...]]
ipython3: error: argument FLAGS: invalid choice: [] (choose from 'X', 'Y', 'Z', 'ALL')
...
Testing an empty list against choices fails:
In [732]: a.choices
Out[732]: ['X', 'Y', 'Z', 'ALL']
In [733]: [] in a.choices
Out[733]: False
In [734]: 'X' in a.choices
Out[734]: True
If we set a valid default:
In [735]: a.default='X'
In [736]: p.parse_args([])
Out[736]: Namespace(FLAGS='X')
This behavior is part of what allows us to use such a positional in a mutually_exclusive_group.
If you don't want to specify a valid default, then changing this to a flagged argument avoids the problem.