argparse Negative Number Positional Breaks With a -1-style Option (tested)
argparse normally lets you pass a negative number like -5 as a plain positional argument. We measured that this only works because of a heuristic — and registering a single-character option such as -1 anywhere on the parser turns it off for the whole program.
1. A negative number positional works fine on its own
import argparse
p = argparse.ArgumentParser()
p.add_argument("value", nargs="?", type=int)
args = p.parse_args(["-5"])
print(args.value)
-5
Measured: with no options that look like negative numbers registered, argparse's heuristic correctly treats -5 as a value, not an option flag, and args.value comes out as -5.
2. Adding an unrelated -1 option breaks it everywhere
p2 = argparse.ArgumentParser()
p2.add_argument("-1", "--one", action="store_true", dest="one")
p2.add_argument("value", nargs="?", type=int)
try:
p2.parse_args(["-5"])
except SystemExit as e:
print("SystemExit code:", e.code)
usage: prog [-h] [-1] [value]
prog: error: unrecognized arguments: -5
SystemExit code: 2
Measured: the only change was adding an unrelated -1/--one flag earlier in the same program. That one addition flips argparse's internal _negative_number_matcher check off for every negative-number-looking argument on this parser — not just -1 itself. -5, which was never registered as an option, now gets rejected as an unrecognized argument instead of being read as the positional value. The error message doesn't mention the real cause (the -1 option existing); it just reports -5 as unrecognized.
3. Fix: separate positionals from options with --
p3 = argparse.ArgumentParser()
p3.add_argument("-1", "--one", action="store_true", dest="one")
p3.add_argument("value", nargs="?", type=int)
args3 = p3.parse_args(["--", "-5"])
print(args3.value)
-5
Measured: putting -- before -5 confirmed working — everything after -- is treated as positional, bypassing the broken heuristic entirely. If you control the CLI's documented usage, requiring -- before negative-number positionals is the reliable fix; the alternative is avoiding single-character numeric-looking option names (like -1) altogether so the heuristic never gets disabled.
Frequently asked questions
Why does argparse reject a negative number as 'unrecognized arguments'?
We measured this happening specifically when the same parser has any option that looks like a negative number (e.g. -1). Registering it disables argparse's heuristic for treating negative-number-looking strings as positional values, program-wide.
Does every negative number argument in argparse fail, or just some?
In our test, only parsers with a -1-style option registered failed; a parser with no such option correctly parsed -5 as a plain positional value.
How do I pass a negative number argument to a Python script using argparse?
We confirmed putting -- before the negative number (e.g. prog -- -5) reliably works, since everything after -- is parsed as positional regardless of the broken heuristic.
What is argparse's negative number heuristic?
Per the argparse source, it's an internal regex check (_negative_number_matcher) that treats a negative-number-looking token as a value instead of an option — but only when the parser has zero options that themselves look like negative numbers.
Is this argparse negative-number bug specific to type=int?
No — we confirmed the failure is about argument parsing itself (whether -5 is treated as an option or a value), which happens before type=int ever gets a chance to run.
Written with AI assistance. Measured on 2026-10-04 with Python 3.13.5's built-in argparse module: parsed a negative-number positional argument with and without a single-character option (like -1) registered on the same parser, and with a -- separator. PlainHeaders is our extension; Python's argparse module is built in.