Environment variables maximum size
Unix-like shells and Windows both limit how much data a new process can receive.
Exceeding the limit produces Argument list too long (E2BIG) on POSIX, or a truncated / rejected command line on Windows.
ARG_MAX is the combined size of the argument vector and the environment block that exec / CreateProcess will accept.
getconf ARG_MAXor from Python:
import os
print(os.sysconf("SC_ARG_MAX"))POSIX defines ARG_MAX as the maximum length of the arguments to the exec family, including environment data.
That means:
- every
argv[i]string (plus its terminating NUL) - every
NAME=valueenvironment string (plus NUL) - implementation-specific accounting for pointer arrays, null terminators, and alignment
On Linux, the executable path is also included in the E2BIG check.
On Linux, GNU xargs reports how much of the ARG_MAX budget the current environment already uses:
true | xargs --show-limitsPOSIX’s guaranteed minimum is only _POSIX_ARG_MAX = 4096 bytes, which could be a consideration on micro embedded systems.
Real systems ARG_MAX values are usually much larger on modern systems.
POSIX does not define a portable way to calculate the exact remaining room because implementations may account for pointers, null terminators, and alignment differently.
Linux
Two independent limits apply.
ARG_MAX: overall combined size of the argument vector and environment block.
- at most 1/4 of the current soft
RLIMIT_STACK - at most 3/4 of the kernel’s
_STK_LIM(8 MiB) → 6 MiB ceiling - at least 32 pages (128 KiB floor, since Linux 2.6.25)
Default stack is 8 MiB, so getconf ARG_MAX is typically 2097152 (2 MiB).
Raising ulimit -s raises the reported value up to the 6 MiB cap; dropping the
stack limit drops ARG_MAX toward 128 KiB.
<linux/limits.h> ARG_MAX header value is a compile-time minimum, not the runtime limit.
Instead, use getconf or sysconf(_SC_ARG_MAX).
MAX_ARG_STRLEN: This is the limit constraining export of a huge variable.
A single argument or environment variable (NAME=value\0) cannot exceed MAX_ARG_STRLEN.
Exceeding MAX_ARG_STRLEN results in execve returning E2BIG, even when the total is well under ARG_MAX.
Raising MAX_ARG_STRLEN requires rebuilding the kernel.
macOS
Darwin does not have Linux’s per-string MAX_ARG_STRLEN cap.
One argument or one environment variable can consume almost the entire ARG_MAX.
Typical values:
| source | typical value |
|---|---|
getconf ARG_MAX |
1048576 (1MiB) |
sysctl kern.argmax |
1048576 (1MiB) |
kern.argmax is not tunable at runtime.
The budget still includes the environment.
A 128 KiB PATH can contribute to exec failures when combined with the rest of the
environment and the command arguments, even though 1 MiB looks ample on paper.
Shell builtins (echo, printf) are not subject to ARG_MAX.
External binaries are.
Windows
Windows splits the problem across several APIs. There is no getconf ARG_MAX.
| Layer | Limit |
|---|---|
CreateProcessW command line |
32,767 characters including the terminating NUL |
CreateProcessA environment block |
32,767 characters |
| Unicode environment block (Vista+) | no documented hard cap; 256 KiB+ works from Win32 |
| Documented max one user-defined env var | 32,767 characters |
cmd.exe command line |
8191 characters |
cmd.exe inherited env var it will honor |
8191 characters |
set in cmd.exe |
8191 characters |
setx |
1024 characters when assigning a value |
So:
- A program calling
CreateProcessWcan pass a ~32k character command line and a large Unicode environment. - Anything that goes through
cmd.exeor a.batfile dies at 8191. - PowerShell and the Win32 APIs can set a single variable closer to the 32,767
character documented max;
cmdcannot.
The environment block format is:
NAME=value\0NAME=value\0\0
Names cannot contain =.
How the two limits interact
Setting a huge variable in the current shell often succeeds.
The failure happens at the next exec:
# Linux: this assignment may work in bash
export HUGE=$(python3 -c "print('x'*200000)")
# this exec fails with E2BIG because 200000 > MAX_ARG_STRLEN
/bin/trueOn macOS the same pattern fails when len("HUGE=")+200000 plus the rest of the environment exceeds ARG_MAX.
On Windows, cmd.exe will not even accept a set line longer than 8191 characters, while CreateProcessW with an explicit environment block can go much further.
Prove the Linux per-string cap
import os, subprocess
for n in (131069, 131070, 131071):
env = os.environ.copy()
env["H"] = "x" * n
try:
subprocess.check_call(["/bin/true"], env=env)
print(n, "ok")
except OSError as e:
print(n, e)On a 4 KiB page Linux kernel, 131069 typically succeeds and 131070 fails because
H= plus the value and the terminating NUL must fit within MAX_ARG_STRLEN.
Workarounds
- Do not put large payloads in the environment or argv. Use a file, pipe, socket, or response file (
@args.txt). xargs/find -exec … {} +chunk argv to stay under the total.- On Linux,
ulimit -sonly helps the total, notMAX_ARG_STRLEN. - On Windows, call
CreateProcessWdirectly (or PowerShell / Pythonsubprocesswithenv=) instead of going throughcmd.exe. - Keep
PATHshort; it is the environment variable that most often eats the budget.
Summary
| Platform | Total argv + env | One environment variable |
|---|---|---|
| Linux (≥ 2.6.25) | ~1/4 of stack, 128 KiB–6 MiB (often 2 MiB) | 128 KiB (MAX_ARG_STRLEN) |
| macOS | 1 MiB (kern.argmax) |
same as total |
| Windows Win32 | 32,767-character command line; large Unicode environment block | 32,767 characters |
Windows cmd.exe |
8191 characters | 8191 characters |
The 128 KiB figure often quoted for Unix is the Linux per-string cap (MAX_ARG_STRLEN), not the total, and not a universal Unix number.