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_MAX

or 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=value environment 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-limits

POSIX’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 CreateProcessW can pass a ~32k character command line and a large Unicode environment.
  • Anything that goes through cmd.exe or a .bat file dies at 8191.
  • PowerShell and the Win32 APIs can set a single variable closer to the 32,767 character documented max; cmd cannot.

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/true

On 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 -s only helps the total, not MAX_ARG_STRLEN.
  • On Windows, call CreateProcessW directly (or PowerShell / Python subprocess with env=) instead of going through cmd.exe.
  • Keep PATH short; 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.