Offloading Large Workflows¶
v2.4 and after
Argo stores workflows as Kubernetes resources (i.e. within EtcD). This creates a limit to their size as resources must be under 1MB. Each resource includes the status of each node, which is stored in the /status/nodes field for the resource. This can be over 1MB. If this happens, we try and compress the node status and store it in /status/compressedNodes. If the status is still too large, we then try and store it in an SQL database.
To enable this feature, configure a Postgres, MySQL, or MariaDB database under persistence in your configuration and set nodeStatusOffLoad: true.
Node Status Compression¶
v4.1 and after
By default node statuses are compressed with gzip. The WORKFLOW_COMPRESSION_ALGORITHM environment variable on the controller selects gzip, zstd, or brotli instead, and WORKFLOW_COMPRESSION_LEVEL tunes the chosen algorithm. Decompression always auto-detects the algorithm, so the variables only affect newly written statuses.
Warning
Workflows written with a non-gzip algorithm cannot be read by Argo versions without support for it (including kubectl-level tooling that gunzips /status/compressedNodes directly). Only change the algorithm after all components are upgraded, and be aware that downgrading past that support leaves in-flight large workflows unreadable.
Levels are algorithm-specific and default to each library's own default: gzip 1–9 (default 6), zstd 1–4 (default 2), brotli 0–11 (default 6).
For context, measurements on synthetic node statuses (sizes are relative to the gzip default, compression times are for ~1MiB and ~10MiB of node status JSON):
| Algorithm | Level | Size vs gzip | Compress 1MiB (ms) | Compress 10MiB (ms) |
|---|---|---|---|---|
gzip |
6 (default) | 100% | 5 | 43 |
zstd |
2 (default) | 88% | 6 | 49 |
zstd |
3 | 82% | 6 | 58 |
brotli |
6 (default) | 72% | 11 | 129 |
brotli |
9 | 67% | 24 | 232 |
brotli |
11 | 59% | 1700 | 18300 |
Decompression speed is roughly equal for all three algorithms (about 9 milliseconds per MiB of JSON). Higher levels than those shown buy little: brotli 11 compresses best but is about 80 times slower than brotli 9, which matters because the controller re-compresses the status on every update of a large workflow. zstd 3 and brotli 9 are good choices when smaller statuses are worth slightly more controller CPU; they raise the effective node-count ceiling before offloading is required by roughly 20% and 50% respectively.
These numbers are from synthetic data; real workflows may compress differently.
FAQ¶
Why aren't my workflows appearing in the database?¶
Offloading is expensive and often unnecessary, so we only offload when we need to. Your workflows aren't probably large enough.
Error Failed to submit workflow: etcdserver: request is too large.¶
You must use the Argo CLI having exported export ARGO_SERVER=....
Error offload node status is not supported¶
Even after compressing node statuses, the workflow exceeded the EtcD size limit. To resolve, either enable node status offload as described above or look for ways to reduce the size of your workflow manifest:
- Use
withItemsorwithParamsto consolidate similar templates into a single parametrized template - Use template defaults to factor shared template options to the workflow level
- Use workflow templates to factor frequently-used templates into separate resources
- Use workflows of workflows to factor a large workflow into a workflow of smaller workflows
Container Arguments Offloading¶
v3.7 and after
When container arguments are extremely large, Argo automatically offloads them to avoid exceeding system limits. This feature addresses two types of argument size issues:
How It Works¶
1. ConfigMap Offloading (over 128KB total args)¶
If a container's JSON marshaled arguments exceed 128KB (131,072 bytes), Argo stores them in a ConfigMap instead of directly in the pod specification:
- Args are stored in a ConfigMap with key
ARGO_CONTAINER_ARGS_FILE - The ConfigMap is mounted as a volume at
/argo/config/ - An environment variable
ARGO_CONTAINER_ARGS_FILEpoints to/argo/config/ARGO_CONTAINER_ARGS_FILE - The emissary executor automatically reads and applies the args at runtime
- Container args in the pod spec are cleared (set to nil)
This happens automatically and transparently - no workflow changes needed.
2. Individual Argument Offloading (over 128KB per arg) with @filename Syntax¶
Even after loading args from the ConfigMap, individual arguments exceeding 128KB (131,072 bytes) would still trigger the exec syscall's "argument list too long" error (E2BIG). To handle this:
- Each argument larger than 128KB (131,072 bytes) is written to
/tmp/argo_arg_N.txt - The argument is replaced with
@/tmp/argo_arg_N.txt - Downstream programs must support the
@filenamesyntax to read the content from the file
Downstream Program Requirements¶
For individual arguments exceeding 128KB, Argo replaces the argument value with @/tmp/argo_arg_N.txt. To enable your container program to handle arguments larger than 128KB, implement file reference expansion by:
- Detecting arguments starting with
@ - Reading the file path after the
@prefix - Using the file contents as the actual argument value
If your program doesn't support this pattern, you'll need to either:
- Add file expansion logic to your program
- Reduce argument sizes below 128KB
- Use alternative input methods (environment variables, mounted ConfigMaps, etc.)
Logging¶
When offloading occurs, you'll see these log messages:
Controller logs:
Offloaded container args to configmap. Args >128KB will use @filename syntax container=my-container
Emissary executor logs:
Reading container args from file argsFile=/argo/config/ARGO_CONTAINER_ARGS_FILE
Loaded container args from file count=5
Offloaded large argument to file. Downstream program must support @filename syntax argIndex=1 size=140000 filePath=/tmp/argo_arg_1.txt
Troubleshooting¶
Error: Program doesn't recognize @filename argument¶
Your program doesn't support the @filename syntax. Options:
- Add file expansion logic to detect
@prefix and read the referenced file - Reduce the argument size below 128KB
- Use alternative input methods (environment variables, mounted ConfigMaps, etc.)
Args not being offloaded when expected¶
- ConfigMap offloading triggers at 128KB total args (131,072 bytes, JSON marshaled)
- Individual arg file offloading triggers at 128KB per argument (131,072 bytes)
- Check controller logs for "Offloaded container args to ConfigMap" message
- Check emissary logs for "Offloaded large argument to file" message