Abstract
This tutorial documents the configuration and use of aria2 to download very large files and LLM weight archives on an NVIDIA Jetson AGX Orin Developer Kit 64 GB running Ubuntu 22.04.5 LTS aarch64 with JetPack 6.2.2. It focuses on high-concurrency HTTPS downloads from Hugging Face and similar model repositories, with commands tuned for edge hardware, multi-gigabyte single-file models in GGUF or safetensors format, and the object storage redirect behavior common to modern model hosting platforms.
The guide covers robust resume strategies using .aria2 control files and session files that allow downloads to survive reboots, intermittent connectivity, and signed URL expiration. Failure scenarios encountered in practice — including HTTP 403 rate limits near completion, hash-like output filenames resulting from redirect chains, and missing control metadata — are addressed with safe, prescriptive recovery steps that avoid data corruption or accidental full re-downloads.
The document targets advanced Linux and Jetson users who regularly fetch multi-GB model artefacts and want a repeatable, resilient pattern for aria2 on ARM64. Readers will finish with a working installation, a set of reusable power commands, a reliable batch-resume workflow, and the knowledge to debug common failure modes without discarding already-downloaded data.
1. Hardware and software environment
The environment documented throughout this tutorial is an NVIDIA Jetson AGX Orin Developer Kit with 64 GB unified memory, running a standard JetPack 6.2.2 software stack on Ubuntu 22.04.5 LTS aarch64. This configuration represents a current-generation edge AI development system with sufficient CPU cores, RAM, and storage throughput to benefit from aria2's parallel download capabilities. The commands and flag values in subsequent sections are validated against this environment.
| Component | Version / Value |
|---|---|
| Hardware | NVIDIA Jetson AGX Orin Developer Kit 64 GB |
| OS | Ubuntu 22.04.5 LTS aarch64 |
| Kernel | 5.15.185-tegra |
| L4T | 36.5.0 |
| JetPack | 6.2.2 |
| CUDA | 12.6 |
| cuDNN | 9.3 |
| TensorRT | 10.3 |
Table 1 — Jetson AGX Orin software stack
The tutorial assumes that network routing, DNS, and internet connectivity to Hugging Face are already functional on the device. No proxy or VPN configuration is assumed, although aria2 supports those if needed. Storage is assumed to be NVMe or SSD formatted as ext4, which affects the recommended file allocation strategy discussed in section 6.
2. Installing aria2
aria2 is available from the official Ubuntu 22.04 aarch64 package repositories and requires no external PPA or manual build on this platform.
sudo apt update
sudo apt install -y aria2
aria2c -v
aria2c -v prints version details and build flags, confirming that the binary is functional and correctly linked. If the command is not found, verify that /usr/bin is in PATH. On a standard Jetson Ubuntu installation, no adjustments are required.
Create dedicated directories for model files and their associated .aria2 control files before starting any downloads. Co-locating them in stable directories is essential for reliable resume behavior, as aria2 expects the data file and its sidecar to share the same directory and base name.
mkdir -p ~/models
mkdir -p ~/downloads
Moving or renaming a data file after a partial download breaks the association aria2 relies on to continue from the correct offset. Establish these directories once and use them consistently across all aria2 invocations.
3. Fast single-file downloads from Hugging Face
3.1 Core throughput flags: -x, -s, and -k
For a single large file, aria2 opens multiple HTTP connections and divides the target into segments that are fetched concurrently. Three flags control this behavior:
-
-x N/--max-connection-per-server=N: number of parallel HTTP connections opened to the server. -
-s N/--split=N: number of segments the file is divided into for parallel download. -
-k SIZE/--min-split-size=SIZE: minimum size per segment (e.g.,64M); prevents excessive small chunks for large files.
The URL must always be the last positional argument. A common mistake is placing -s immediately before the URL with no numeric value between them, which causes aria2 to interpret the URL as the split count and fail silently.
Correct usage for a Hugging Face GGUF file:
aria2c -x 16 -s 16 \
"https://huggingface.co/unsloth/gemma-4-31B-it-GGUF/resolve/main/gemma-4-31B-it-Q4_K_M.gguf?download=true"
If the server returns HTTP 429 responses or imposes rate limits, reduce concurrency:
aria2c -x 8 -s 8 \
"https://huggingface.co/unsloth/gemma-4-31B-it-GGUF/resolve/main/gemma-4-31B-it-Q4_K_M.gguf?download=true"
Example of download command to download gemma-4-26B-A4B-it-UD-Q4_K_M.gguf
aria2c \
-c \
-x8 -s8 \
-k32M \
--retry-wait=10 \
--max-tries=0 \
--file-allocation=none \
--summary-interval=60 \
-o gemma-4-26B-A4B-it-UD-Q4_K_M.gguf \
'https://huggingface.co/unsloth/gemma-4-26B-A4B-it-GGUF/resolve/main/gemma-4-26B-A4B-it-UD-Q4_K_M.gguf?download=true'
3.2 Power command template for large model downloads
The following command is the recommended baseline for large model downloads. It combines high concurrency with resilient retry behavior, explicit resume support, and a stable output filename.
aria2c -c -x16 -s16 -k64M \
--retry-wait=5 --max-tries=0 \
--file-allocation=none \
--summary-interval=60 \
-d ~/models \
-o gemma-4-31B-it-Q4_K_M.gguf \
"https://huggingface.co/unsloth/gemma-4-31B-it-GGUF/resolve/main/gemma-4-31B-it-Q4_K_M.gguf?download=true"
Flag-by-flag explanation:
-
-c/--continue=true: resume an existing partial file if the.aria2control file is present. -
-x16/-s16: 16 parallel connections and 16 file segments for maximum throughput on a fast link. -
-k64M: 64 MB minimum segment size; reduces the number of chunks for very large files. -
--retry-wait=5: pause 5 seconds before each retry on transient errors. -
--max-tries=0: retry indefinitely; aria2 will not give up until stopped manually. -
--file-allocation=none: skip pre-allocation of the full file size, avoiding a blocking write at startup on Jetson NVMe storage. -
-d ~/models: explicit target directory. -
-o <filename>: explicit output filename, preventing query-string characters or hash-like object keys from appearing in the filename on disk.
For throttled or unstable connections, use the conservative variant:
aria2c -c -x8 -s8 -k16M \
--retry-wait=10 --max-tries=0 \
--file-allocation=none \
-d ~/models \
"https://huggingface.co/.../model.gguf?download=true"
This reduces pressure on the server while still delivering substantially better throughput than a single connection.
4. Resume mechanics and .aria2 Control Files
4.1 How aria2 resume works
For every active download, aria2 creates a binary control file alongside the data file using the naming convention <target-filename>.aria2. Downloading model.gguf produces both model.gguf and model.gguf.aria2 in the output directory. The control file tracks segment byte offsets, checksums, and download state. Without it, aria2 cannot determine which byte ranges are valid and cannot safely resume.
If the same aria2 command is re-run from the same directory with the same output filename, aria2 detects the existing data file and its .aria2 sidecar and continues from the last recorded position. The -c flag makes this behavior explicit and causes aria2 to abort rather than silently overwrite when a safe resume is not possible.
# First run — interrupted partway through
aria2c -c -x16 -s16 -k64M -o model.gguf "https://huggingface.co/.../model.gguf"
# Second run — resumes from the interrupted position
aria2c -c -x16 -s16 -k64M -o model.gguf "https://huggingface.co/.../model.gguf"
To enforce strict resume-or-abort behavior rather than a silent restart:
aria2c --always-resume=true -c "https://example.com/bigfile.iso"
4.2 Missing .aria2 control file
If aria2 reports errorCode=13 or a message containing "file exists but .aria2 does not exist", the data file is present but the control file has been lost.
- If the data file is complete and passes an integrity check (e.g., SHA-256 matches the repository-published hash), it can be kept and removed from any pending URL or session lists.
- If the data file is incomplete and the
.aria2file is gone, aria2 has no record of which byte ranges were successfully written. The safest recovery is to delete both the partial data file and any remnant.aria2file, then restart the download from scratch for that specific file.
Do not attempt to resume an incomplete file without its control file. The resulting output may silently contain duplicate or missing byte ranges.
4.3 Resuming with a new signed URL
Hugging Face and similar hosts issue time-limited signed URLs. If a partial download's original URL has expired, resume is still possible provided:
- The output file name and directory path are unchanged.
- The new URL resolves to the same file content.
aria2c -c --auto-file-renaming=false \
-d ~/models -o model.gguf \
"https://new-signed-url..."
The --auto-file-renaming=false flag prevents aria2 from creating a renamed copy (e.g., model.gguf.1) when it detects an existing file. Instead, aria2 reuses the existing partial file and its .aria2 control file and continues from the recorded position.
5. Batch downloads and session files
5.1 URL list with session management
When downloading multiple files — such as a full safetensors shard set or several GGUF quantization variants — use a URL list file and a session file to enable batch resume. Create urls.txt with one URL per line:
https://huggingface.co/.../model-00001-of-00037.safetensors
https://huggingface.co/.../model-00002-of-00037.safetensors
https://huggingface.co/.../model-00003-of-00037.safetensors
Start the batch with session tracking enabled:
aria2c -i urls.txt \
--save-session=aria2-session.txt \
--save-session-interval=60 \
-c -x8 -s8 -k16M \
-d ~/models
-
-i urls.txt: read download targets from the URL list file. -
--save-session=aria2-session.txt: write all active and incomplete download state to the session file. -
--save-session-interval=60: flush the session file to disk every 60 seconds, limiting lost progress on an abrupt stop. -
-c: resume any partial files found in the target directory.
After a reboot or manual stop, resume the entire batch:
aria2c --input-file=aria2-session.txt \
--save-session=aria2-session.txt \
-c
--input-file reloads all entries from the session file. Completed downloads are automatically dropped from the next session write. Adding --force-save=true retains completed entries for audit purposes, but requires manual pruning of the session file as the download set grows.
5.2 Persistent single-session workflow
A single session file can serve as both input and output, providing a self-maintaining queue of unfinished downloads across multiple aria2 invocations.
touch aria2-session.txt
aria2c --input-file=aria2-session.txt \
--save-session=aria2-session.txt \
--save-session-interval=30 \
-c -x8 -s8 -k16M \
-d ~/downloads
New URLs can be added to the queue at any time by running a separate aria2c -i urls.txt ... --save-session=aria2-session.txt invocation. The session file accumulates all unfinished tasks and the next resume run picks them all up automatically.
6. Jetson-specific configuration and filesystem Considerations
6.1 Recommended baseline flags for Jetson AGX Orin
The Jetson AGX Orin has fast CPU cores and ample RAM, but disk throughput and storage capacity may be shared across concurrent inference workloads. The following practices are tuned for this profile:
- Use a dedicated directory per model project (
~/models,~/hf_cache) to keep.aria2control files co-located with their data files and avoid cross-directory confusion. - Prefer
--file-allocation=nonefor fast startup. Switch tofalloconly when pre-allocation is explicitly needed for fragmentation control on large multi-GB artefacts. - Start with
-x8 -s8and increase to 16 if the connection and server support it without triggering rate limiting. - Always include
-cfor any file larger than a few hundred megabytes to guard against accidental restarts.
Add a shell alias to ~/.bashrc to standardize the baseline:
echo "alias aria2fast='aria2c -c -x8 -s8 -k16M --file-allocation=none --summary-interval=30'" >> ~/.bashrc
source ~/.bashrc
Usage with the alias:
aria2fast -d ~/models -o model.gguf "https://huggingface.co/.../model.gguf?download=true"
A Hugging Face-specific alias with longer retry delays handles the backend's rate limiting more gracefully:
echo "alias hfaria='aria2c -c -x8 -s8 -k32M --retry-wait=10 --max-tries=0 --file-allocation=none --summary-interval=60'" >> ~/.bashrc
source ~/.bashrc
6.2 File allocation on Jetson NVMe
On the Jetson NVMe (ext4 with extents), --file-allocation=falloc pre-allocates the full file using fallocate(2), which is fast and reduces fragmentation for multi-GB files. On slower or older filesystems, --file-allocation=none avoids a blocking write pass at startup.
aria2c -c -x8 -s8 -k32M \
--file-allocation=falloc \
-d ~/models \
"https://huggingface.co/.../model.gguf?download=true"
Monitor available storage before long downloads with df -h. An out-of-space condition frequently manifests as repeated failures at the same completion percentage, which can be misread as a network or server error.
7. Filename issues from redirect chains
7.1 Why downloads receive hash-like filenames
When downloading from a Hugging Face resolve URL, the server redirects through an internal S3-style backend (cas-bridge.xethub.hf.co or similar object storage). The final HTTP response path contains an opaque SHA-like object key rather than the human-readable model filename. If no explicit output name is provided with -o, aria2 saves the file using that object key as the filename, producing output such as:
c56b8f0416a453a53aace7bef4a088a2c2db33c3b8a4eda949a380c214420b31
The fix is to always specify -o with the intended filename. This flag forces the output name regardless of redirects or Content-Disposition headers:
cd ~/models
aria2c -c -x8 -s8 -k32M \
--file-allocation=none \
-o gemma-4-31B-it-Q4_K_M.gguf \
"https://huggingface.co/unsloth/gemma-4-31B-it-GGUF/resolve/main/gemma-4-31B-it-Q4_K_M.gguf?download=true"
7.2 Renaming an existing hash-named partial file
If a large partial download was already saved under a hash name, it can be renamed without discarding the downloaded data. Both the data file and its .aria2 sidecar must be renamed to matching names simultaneously:
cd ~/models
mv c56b8f0416a453a53aace7bef4a088a2c2db33c3b8a4eda949a380c214420b31 \
gemma-4-31B-it-Q4_K_M.gguf
mv c56b8f0416a453a53aace7bef4a088a2c2db33c3b8a4eda949a380c214420b31.aria2 \
gemma-4-31B-it-Q4_K_M.gguf.aria2
After renaming, re-run the standard aria2 command with -o gemma-4-31B-it-Q4_K_M.gguf from the same directory. aria2 will locate the renamed pair and resume only the missing segments.
8. Failure modes and recovery
8.1 HTTP 403 errors during download (errorCode=22)
Error lines of the form errorCode=22 … status=403 indicate that individual HTTP segment requests were rejected by the backend. This occurs most commonly near the end of a long download from Hugging Face for two reasons:
- Signed S3 URLs in the redirect chain expire mid-download on very large or slow-connection transfers.
- High concurrency (
-x16 -s16) triggers per-connection rate limiting on popular models.
When errorCode=22 appears but the download ultimately reports stat|OK, aria2 recovered and retried successfully. To reduce the frequency of these errors:
aria2c -c -x8 -s8 -k32M \
--retry-wait=10 --max-tries=0 \
--file-allocation=none \
-o gemma-4-31B-it-Q4_K_M.gguf \
"https://huggingface.co/unsloth/gemma-4-31B-it-GGUF/resolve/main/gemma-4-31B-it-Q4_K_M.gguf?download=true"
Lower -x/-s values reduce the number of simultaneous signed segment requests in flight. Combined with --retry-wait=10 and --max-tries=0, aria2 waits calmly between retries rather than hammering the backend.
8.2 Persistent failures at a fixed byte offset
When a download fails repeatedly at the same percentage or offset:
- Reduce
-xand-sto lower concurrent byte-range requests. - Increase
--retry-wait(e.g.,--retry-wait=30) and keep--max-tries=0to allow extended retry cycles. - Check for local storage or filesystem errors with
dmesgandjournalctl -xe. Write errors on Jetson NVMe can present as download failures at the application layer. - If the
.aria2control file is corrupted and resume fails consistently, delete both the partial data file and the.aria2file, then restart that specific download only — not the entire batch.
8.3 Quick command reference
| Use case | Command |
|---|---|
| Fast single model download | aria2c -c -x16 -s16 -k64M --file-allocation=none -d ~/models -o FILE "URL" |
| Conservative single model | aria2c -c -x8 -s8 -k16M --file-allocation=none -d ~/models -o FILE "URL" |
| Resume single file |
aria2c -c -x8 -s8 -o FILE "URL" (run from same dir, .aria2 present) |
| Batch from URL list | aria2c -i urls.txt --save-session=aria2-session.txt -c -x8 -s8 -d ~/models |
| Resume batch via session | aria2c --input-file=aria2-session.txt --save-session=aria2-session.txt -c |
| New signed URL for partial | aria2c -c --auto-file-renaming=false -d DIR -o FILE "NEW_URL" |
| Retain completed in session | Add --force-save=true; prune session file manually as needed |
Table 2 — aria2 command reference for Jetson AGX Orin
9. Practical outcomes
- Established a correct and efficient aria2 command pattern for large Hugging Face model downloads on Jetson AGX Orin, including proper flag ordering for
-x,-s, and-k, and the mandatory use of-oto avoid hash-like filenames from object storage redirects. - Documented resume mechanics using
.aria2control files, the-cflag, and--always-resume=true, with explicit guidance on what to do when the control file is missing or the data file has been renamed. - Provided a signed-URL resume pattern using
--auto-file-renaming=falsethat handles expiring links without restarting partial downloads. - Defined batch download patterns using URL list files and persistent session files (
--save-session,--input-file) for multi-shard model repositories such as safetensors split sets. - Captured Jetson-specific defaults covering file allocation modes (
nonevs.falloc), directory hygiene, concurrency tuning, disk space monitoring, and error recovery for long-running downloads. - Identified the root cause of HTTP 403 (
errorCode=22) errors during large Hugging Face downloads as expiring signed URLs and per-connection rate limiting, with a prescriptive mitigation using reduced concurrency and extended retry delays.
10. Conclusions and recommendations
aria2 reliably saturates available bandwidth for large LLM downloads on Jetson AGX Orin and handles interruptions gracefully, provided three practices are consistently followed: always pass -c for large files; use a stable output directory so .aria2 control files remain co-located with their data files; and set --max-tries=0 so aria2 recovers from transient failures without manual intervention.
For daily workflows, standardize on one or two shell aliases (aria2fast, hfaria) and always invoke aria2 from the same directory paths. Always specify -o with an explicit filename when downloading from Hugging Face, as the platform's object storage backend assigns opaque hash-like keys that aria2 will use as the filename in the absence of an explicit override. This eliminates the most common source of filename confusion and simplifies subsequent resume operations.
When troubleshooting stubborn failures, apply interventions in order: reduce concurrency first, then increase retry delay, then inspect disk and filesystem health with dmesg and journalctl. Delete a partial file and its .aria2 sidecar only as a last resort, and only for the specific file that is failing — not for the entire batch. If a transient Hugging Face backend outage is causing persistent 403 errors near completion, the most effective response is to wait and retry rather than to restart a near-complete multi-gigabyte download from scratch.
Top comments (0)