argparse Subparsers Not Required by Default (tested)

add_subparsers() looks like it defines a mandatory choice — run, build, whatever your sub-commands are. We measured what happens when a user runs the program with none of them, and argparse doesn't consider that an error.

1. parse_args([]) succeeds with no sub-command chosen

import argparse

p = argparse.ArgumentParser()
sub = p.add_subparsers(dest="cmd")
run_parser = sub.add_parser("run")
run_parser.add_argument("--x")

args = p.parse_args([])
print(args)
Namespace(cmd=None)

Measured: running the program with zero arguments doesn't raise a usage error. args.cmd is just None. Nothing in the run sub-parser ran, so none of its arguments — including --x — were ever added to the namespace at all.

2. Accessing the missing sub-command's argument fails later, not here

try:
    print(args.x)
except AttributeError as e:
    print("AttributeError:", e)
AttributeError: 'Namespace' object has no attribute 'x'

Measured: the failure isn't at parse_args(), where the actual problem (no sub-command given) happened — it's an AttributeError wherever the code first reads args.x, which could be dozens of lines and several function calls away. There's no usage message pointing back to the missing sub-command, just a generic missing-attribute crash at an unrelated line.

3. Fix: pass required=True to add_subparsers()

p2 = argparse.ArgumentParser()
sub2 = p2.add_subparsers(dest="cmd", required=True)
run_parser2 = sub2.add_parser("run")
run_parser2.add_argument("--x")

try:
    p2.parse_args([])
except SystemExit as e:
    print("SystemExit code:", e.code)
usage: prog [-h] {run} ...
prog: error: the following arguments are required: cmd
SystemExit code: 2

Measured: adding required=True (available since Python 3.7) makes parse_args([]) print a proper usage error and exit with code 2 — the standard argparse failure mode for missing required arguments — instead of silently returning a namespace that's missing everything the chosen sub-command would have added. This is opt-in, not the default, so every add_subparsers() call that's meant to be mandatory needs it explicitly.

Frequently asked questions

Are argparse sub-commands required by default?

No — we measured parse_args([]) succeeding with no sub-command chosen and dest set to None, unless add_subparsers() is called with required=True.

Why do I get AttributeError on an argparse Namespace instead of a usage error?

We confirmed that when no sub-command is chosen and subparsers aren't required, none of that sub-command's arguments are added to the Namespace at all, so accessing them later raises AttributeError far from the real cause.

How do I make an argparse sub-command mandatory?

We verified passing required=True to add_subparsers() (available since Python 3.7) makes parse_args() print a usage error and exit with status 2 when no sub-command is given.

What does add_subparsers(dest='cmd') do if no sub-command is required?

We measured args.cmd being set to None when the user gives no sub-command and required isn't set, rather than argparse raising any error.

Does Python's argparse treat missing sub-commands as an error automatically?

In our test, no — argparse only enforces a sub-command choice if you explicitly set required=True on add_subparsers(); without it, an empty command line parses successfully.

Written with AI assistance. Measured on 2026-10-04 with Python 3.13.5's built-in argparse module: built a parser with add_subparsers() and a sub-command-only argument, then called parse_args([]) with no sub-command given, both with and without required=True. PlainHeaders is our extension; Python's argparse module is built in.