argparse subcommands are optional by default; pass required=True and dest
Tested on CPython 3.9.25, 3.11.18, 3.12.16, 3.14.10 and 3.15.2. With sp = parser.add_subparsers(); sp.add_parser('build'), running the tool with no subcommand does not error. parse_args([]) returns an empty Namespace(), so a later args.func(args) (from the set_defaults(func=...) pattern) or args.cmd fails with AttributeError, far from the real cause. add_subparsers(required=True) makes it exit 2, but the message names the choices list: 'the following arguments are required: {build}'. Adding dest='cmd' as well gives 'the following arguments are required: cmd' and stores the chosen name in args.cmd. The old TypeError for required=True without dest (sequence item 0: expected str instance, NoneType found) did not occur on any of these versions, so advice that dest is mandatory to avoid a crash is outdated, though dest is still worth setting.