Skip to content

Fix model download resume with RFC-compliant Range requests - #1250

Open
Carton wants to merge 1 commit into
lightvector:masterfrom
Carton:fix/model-download-resume-rfc-range
Open

Fix model download resume with RFC-compliant Range requests#1250
Carton wants to merge 1 commit into
lightvector:masterfrom
Carton:fix/model-download-resume-rfc-range

Conversation

@Carton

@Carton Carton commented Sep 3, 2026

Copy link
Copy Markdown

Summary

  • Send RFC 7233-compliant Range: bytes=start-end headers when resuming model downloads.
  • Validate response status and Content-Range before appending data.
  • Discard untrusted partial data and fall back to a clean download when Range is ignored or malformed.
  • Keep interrupted full downloads on the normal retry budget when Range is unavailable.

Validation

  • Built the katago executable successfully.
  • Ran the built-in test suite successfully.
  • Verified three fresh-base-dir downloads with controlled mid-stream connection drops; each resumed from the partial offset, completed downloading full file, and passed SHA-256/model loading validation.

The contribute client already tried to resume interrupted model downloads
by appending to the partial file and sending a Range header for the
remaining bytes. However, the header omitted the byte-range unit required
by RFC 7233, for example:

    Range: 100000000-211558521

instead of:

    Range: bytes=100000000-211558521

RFC-compliant servers treat the malformed header as if no Range was sent
and reply 200 with the full content. The client then appended the full body
at the old offset, corrupting the file. The receiver stopped once
totalDataSize exceeded the expected size, and the
"totalDataSize >= modelInfo.bytes" entry condition then returned a bogus
success. This surfaced as the confusing error "Model file was incompletely
downloaded, only got 271379114 bytes out of 271375520", after which the
outer retry loop restarted the entire download. On flaky links this made
every interruption cost a full re-download.

The model host (media.katagotraining.org, GCS behind Cloudflare) supports
Range requests when the header is well formed, returning 206 to a curl -r
request.

Fixes:

- Send "Range: bytes=start-end" so compliant servers return 206 and the
  append-and-continue logic resumes correctly.

- Validate status and Content-Range before streaming the response body. If
  a resumed request receives 200, or receives 206 with a missing or
  unexpected Content-Range, reject the body, discard the partial file,
  remember that Range is unavailable, and restart from byte 0.

- Replace the "totalDataSize >= modelInfo.bytes" early return with an
  explicit overshoot check. Only retained bytes count as partial success;
  discarded data and interrupted full downloads after Range fallback
  consume the normal retry budget rather than resetting it indefinitely.

- Reject non-200/206 response bodies before they can be written to the
  model file.

- Log "Resuming download of model at byte N" when a retry resumes.

Verification included the official katagotraining.org API and a local
model mirror simulating two failure modes: (A) Range honored plus a
mid-stream connection drop, resuming via 206 from the dropped offset; and
(B) Range ignored with a 200 response plus a connection drop, falling back
to a clean full download. Both produced the expected sha256. The combined
change also builds successfully and passes the built-in test suite.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant