CLI AI

Resume an interrupted curl download without corrupting it

2026-06-29

The direct check is curl -sI https://example.com/big.iso | grep -i 'accept-ranges' — no Accept-Ranges: bytes in the response means the server can't resume anything, and -C - won't save you. Skip that check and you can hit curl's ugliest failure mode: it exits with code 0, prints nothing alarming, and leaves you a file that's silently truncated. This walks through resuming properly, catching that failure, retrying, and confirming the result is actually whole.

1. Can the server resume downloads at all?

clai
$ clai check if the server supports resuming downloads→ curl -sI https://example.com/big.iso | grep -i 'accept-ranges'

No Accept-Ranges: bytes in the response means resuming is impossible in principle, and -C - isn't going to change that. Thirty seconds of checking saves an hour of pain when a big download drops near the end.

2. Resuming a normal download

clai
$ clai resume this interrupted download→ curl -C - -O https://example.com/big.iso

-C - tells curl to figure out the offset itself from the local file's size. -O saves it under the name from the URL. If the file's already complete, curl just says there's nothing left to fetch.

3. The trap: the server doesn't support Range

clai
$ clai download the file and verify it came through complete→ curl -C - -o part.bin http://example.com/big.bin && cmp -s part.bin original.bin && echo intact || echo TRUNCATED

This is the line the whole article exists for. When a server ignores Range, curl still exits 0 — no error, no warning — and the file stays cut off exactly where it stopped. Tested against a real server: 51200 bytes landed instead of 200000, with not a single error message anywhere. Never trust a resumed download without checking it — by size, by cmp, or by checksum.

4. Retrying until the download finishes

clai
$ clai download this file with retries until it fully downloads→ curl --retry 10 --retry-delay 5 --retry-all-errors -C - -O https://example.com/big.iso

--retry covers network failures, --retry-all-errors extends that to 5xx responses too. Combined with -C -, every retry continues from where the last attempt stopped instead of starting over.

5. Capping the speed so you don't saturate the link

clai
$ clai download the file but cap it at one megabyte per second→ curl --limit-rate 1M -C - -O https://example.com/big.iso

Useful on a box where something else still needs the bandwidth. Accepts k, M, and G suffixes.

6. Verifying you got the right file

clai
$ clai verify the checksum of the file you just downloaded→ curl -sO https://example.com/big.iso.sha256 && sha256sum -c big.iso.sha256

The last step of any resumed download. A matching checksum is the only real proof that a file stitched back together from pieces is intact — size can match while the content doesn't.

Gotchas

  • curl never tells you a resume failed. Exit code 0, file truncated. Checking after the fact is the only real defense.
  • If the file changed on the server mid-resume, you get garbage. Bytes from the old version and the new one end up spliced into one file. When in doubt, delete the partial file and start clean.
  • -C - plus an -o pointing at a leftover file is dangerous. curl resumes whatever's already at that path — the filename is the only thing it checks, not where the bytes came from.

Related questions

wget or curl? wget -c does the same resume logic and is simpler for a single file. curl is more flexible in scripts and shows up on boxes where wget never got installed.

How do I resume a download over ssh? rsync --partial --progress --append-verify — it resumes and verifies the part you already have.

What does "bad download resume" mean? curl couldn't pick up from the right offset — the server doesn't support Range, or the file changed underneath it. Start over from zero.

See also

Stop guessing which curl flags a resumed download needs — describe it and CliAI writes the command. Install it in one line.