SOFTWARE / SYSTEMS / AIEngineering news. Technical depth.
Architecture / 3 MIN READ

How can a resumed download avoid combining bytes from different file versions?

Use conditional range requests tied to a stable representation. Store a validator with the partial file and resume only with Range plus If-Range; otherwise restart from byte 0.

A safe resumed download must be tied to the exact representation you started with. In HTTP, the practical contract is: save the partial bytes together with a strong validator, then resume with Range plus If-Range. If the validator still matches, the server may send just the missing bytes; if it does not, the server sends the entire current representation instead, which is your signal to discard the partial file and restart. RFC 9110 defines that ordering boundary.

What contract actually prevents mixed versions?

The key is not “did I check the file earlier,” but “did the server evaluate my range request against the same representation at response time?” If-Range provides that boundary. You send either an entity-tag or HTTP-date with the range request. Per RFC 9110, the server returns the range only if the validator matches; otherwise it ignores the range and returns the full representation.

For engineering use, prefer a strong ETag when the origin provides one. A strong validator is representation-specific, which is what you need when stitching bytes together. Use an HTTP-date from Last-Modified in If-Range only when no entity-tag is available and that date qualifies as a strong validator under RFC 9110 section 8.8.2.2, as required by section 13.1.5. If you cannot establish both prerequisites, discard the partial representation and restart.

What does a correct resume flow look like?

Worked example:

  1. Initial request: GET /artifact.tar.zst
  2. Save:
    • bytes 0-1048575
    • total length if known
    • ETag: "abc123"
    • any representation-shaping request headers you used, especially Accept-Encoding
  3. Resume later with the same representation request headers:
GET /artifact.tar.zst
Range: bytes=1048576-
If-Range: "abc123"
Accept-Encoding: identity

Outcomes:

  • 206 Partial Content: verify that Content-Range starts at the saved offset and describes the expected representation before appending the returned bytes. Reject inconsistent ranges.
  • 200 OK: the server returned the full representation, so do not append. Replace the partial file and restart from byte 0.

That fallback matters because it prevents “half old, half new” files without requiring a separate check-then-download round trip.

Where do implementations get this wrong?

Two places show up repeatedly.

First, clients store only the offset and URL, then resume with Range alone. That can silently combine bytes from different versions if the object changed between requests.

Second, clients forget that ranges apply to the selected representation, not some abstract underlying file. If your first request got gzip-compressed bytes and the second gets identity bytes, offsets no longer line up. Keep the representation stable across attempts, often by requesting Accept-Encoding: identity for downloadable artifacts.

If you use object storage, the same rule still applies. Amazon S3 GetObject supports retrieving objects and specific versions, and its API documents access to an object “or version” plus permission differences when a versionId is supplied in the request. If your bucket uses versioning, resuming against a fixed version identifier is even better than resuming against the mutable latest object name, while still using normal HTTP range semantics on the response path. See the Amazon S3 GetObject API.

When should you restart instead of resume?

Use this checklist:

  • No stored validator: restart.
  • Validator mismatch led to 200 OK: restart.
  • Representation request headers changed, especially content encoding: restart.
  • Server does not honor ranges reliably for this endpoint: restart.
  • You switched from current object name to a different object version or key: restart unless you know bytes are identical.

Follow-up: Is HEAD required before resuming?

No. If-Range is better than a preflight HEAD because the server evaluates the condition and the range together on the actual response.

Follow-up: What if the server only gives Last-Modified?

Only use that date in If-Range if no entity-tag is available and the date qualifies as a strong validator under RFC 9110 section 8.8.2.2. Otherwise restart the download. Prefer a strong ETag whenever the server provides one.

Reviewed: 2026-09-05

SOURCES & REVIEW

Sources are linked throughout this guide. Product capabilities can change; consult the linked documentation for your deployment.

Read our editorial approach ↗