Self-Healing CI: Recovering a Failed Gradle Distribution Download
A Gradle wrapper that cannot download its distribution hit a network blip on a large fetch at setup, not a broken build -- the same distribution downloads on a retry.
The problem
A Gradle build fails before any task runs because the wrapper could not download the Gradle distribution -- a timeout, reset, or partial transfer. The distribution URL is valid and the version exists; the large fetch hit a transient network problem. A human re-runs the job and the wrapper provisions cleanly.
Exception in thread "main" java.net.SocketTimeoutException: Read timed out
while downloading https://services.gradle.org/distributions/gradle-8.7-bin.zipWhy it happens
The Gradle wrapper provisions the toolchain by downloading a sizeable distribution archive on first use, and a single large transfer is more exposed to a brief network blip or a momentary 5xx than a small request would be.
It is a setup-time fetch failure, not a build problem: the wrapper config and version are correct, and the same distribution provisions once the download is retried or served from a cache.
The manual fix
Manual mitigations for a Gradle distribution download:
- Re-run the job to retry the wrapper download.
- Cache the Gradle distribution and
~/.gradlebetween runs so it is not re-downloaded each time. - Point the wrapper at an internal mirror of the distribution to reduce dependence on the public host.
./gradlew --no-daemon build || (sleep 5 && ./gradlew --no-daemon build)How this gets automated
A failed distribution download has a recognizable transient signature -- a timeout or partial transfer on a large fetch at setup -- and the safe response is to retry, ideally from a cache. A self-healing CI pipeline detects the provisioning failure, retries the download, and only escalates if the distribution is genuinely unreachable across retries, distinguishing a blip from a real version or availability problem.