You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Toolchain download restarts from zero at ~90MB and never completes (no resume) #1370
fbuild cannot provision the ARM toolchain on Windows: the download of arm-gnu-toolchain-15.2.rel1-mingw-w64-x86_64-arm-none-eabi.zip (282 MB) restarts from zero every time it reaches roughly 80–98 MB, and never completes.
Reproduced via bash compile samd21 --examples Blink in FastLED, which drives fbuild <dir> build -e samd21.
Observed
Parsed from the progress output of a single invocation:
Roughly 450 MB transferred for zero net progress, and the run still had not produced a toolchain. Every attempt dies in the same 80–98 MB band, which reads like a timeout or a dropped connection rather than a random network fault.
Impact
Two distinct problems, and the second is the serious one:
No resume. The partial file is discarded on failure. Accept-Ranges: bytes is advertised by the ARM developer host, so a ranged retry would pick up where it left off. Instead each retry pays full price.
No progress across retries, so it cannot converge. Because every attempt starts at 0 and dies around the same offset, more retries do not help. This is not slow — it is non-terminating. On a connection where a 282 MB single stream cannot survive ~90 MB, fbuild can never provision this toolchain at all.
This blocked local verification of a SAMD fix (FastLED/FastLED#4015); I had to fall back to CI, where the toolchain is already provisioned.
Suggested handling
Retry with Range: from the byte count already on disk rather than restarting.
Cap retries and fail loudly with the byte offset, instead of looping indefinitely at the same place.
Verify the completed archive by digest, so a resumed download is still provably intact.
Segmented/parallel fetch would also help, but resume is the part that changes whether it finishes rather than how fast. Related: FastLED/FastLED#3968 and forge-ci/zccache#1469 make the same case for a content-addressed fetch with conditional GET, measured at 3.7x on a comparable payload; a shared implementation would cover both.
So each failed attempt discards everything. Latest run before I gave up: 9 resets, peak 116/282 MB, roughly 1 GB transferred for zero progress. Retries cannot help when every attempt starts at byte 0 and the connection does not survive ~100 MB.
The same download, with Range:
curl -sL -C - --retry 3 -o armgcc.zip <url> # in a retry loop
COMPLETE at attempt 2 (295922350 bytes)
Two attempts. Byte-exact, valid zip, 7801 entries. The origin advertises what is needed:
HTTP/1.1 200 OK
Content-Length: 295922350
Accept-Ranges: bytes
So the fix is not more retries or a longer timeout — it is write to disk and resume from the byte count already there. That single change turns a non-terminating download into a two-attempt one on this connection.
Seeding the cache by hand works
For anyone else blocked: extracting into the install layout is enough, fbuild picks it up with no further download.
The ARM zip is already flat at its root, so it extracts straight in. Layout confirmed against toolchain-gccarmnoneeabi-teensy in the same cache. Remove the stale .install.lock and empty _staging left by the killed run.
arm-none-eabi-g++.exe (Arm GNU Toolchain 15.2.Rel1 (Build arm-15.86)) 15.2.1 20251203
Worth noting the marker is what makes hand-seeding viable, and also what makes the current failure total: a half-extracted staging dir with no marker leaves no usable state behind either.
Activity
zackees commentedon Aug 23, 2026
Worked around it locally, and the workaround identifies the fix precisely.
Why it cannot converge
There is no partial file on disk to resume from. The cache dir shows only a staging directory and a lock:
So each failed attempt discards everything. Latest run before I gave up: 9 resets, peak 116/282 MB, roughly 1 GB transferred for zero progress. Retries cannot help when every attempt starts at byte 0 and the connection does not survive ~100 MB.
The same download, with
Range:Two attempts. Byte-exact, valid zip, 7801 entries. The origin advertises what is needed:
So the fix is not more retries or a longer timeout — it is write to disk and resume from the byte count already there. That single change turns a non-terminating download into a two-attempt one on this connection.
Seeding the cache by hand works
For anyone else blocked: extracting into the install layout is enough, fbuild picks it up with no further download.
The ARM zip is already flat at its root, so it extracts straight in. Layout confirmed against
toolchain-gccarmnoneeabi-teensyin the same cache. Remove the stale.install.lockand empty_stagingleft by the killed run.Worth noting the marker is what makes hand-seeding viable, and also what makes the current failure total: a half-extracted staging dir with no marker leaves no usable state behind either.
refactor(download): move the downloader tests into their own file
fix(download): never append a 416 body, and bound the retry loop abso…
fix(fetch): flush partial progress when a download connection drops
fix(fetch): flush partial progress when a download connection drops (#…