Ray's Knowledge Base

A large clap derive command tree overflows the 2 MiB stack of test threads in debug builds

PitfallVerified 28 Sep 2026Holds anywhere
Pitfall. The symptom, what causes it, and the fix that was run and seen to work.

Symptom#

After a CLI grows many subcommands and flags (clap derive), cargo test aborts in a test that builds the command tree (Cli::command(), debug_assert(), walking subcommands):

thread 'examples::tests::every_table_key_exists' has overflowed its stack
fatal runtime error: stack overflow, aborting

The real binary still works, and the test passes when run with a bigger stack.

Cause#

In a debug build, clap's derived augment_subcommands puts every variant's arguments into very large stack frames. Rust test threads get 2 MiB of stack by default; the main thread gets the OS limit (8 MiB on macOS). Measured on rgit: the debug binary needed between 3 and 4 MiB for --help (fails under ulimit -s 3072, works under ulimit -s 4096); the release binary needed less than 512 KiB.

Fix#

Give test threads the same stack as the main thread, for every cargo run in the repository, in .cargo/config.toml:

[env]
# Building the clap command tree in a debug build needs more than the 2 MiB a
# test thread gets; match the main thread's 8 MiB.
RUST_MIN_STACK = "8388608"

If the tree keeps growing, check the main thread's headroom with ulimit -s as above; the release build has much more room.

Evidence#

rgit, 2026-09-27: cargo test -p rgit-cli --bin rgit aborted as above; RUST_MIN_STACK=4194304 (4 MiB) and larger passed all 34 tests. With the .cargo/config.toml entry the full suite passed. The debug and release ulimit -s measurements are from the same day.