Keep one failure from aborting a batch install - #23525
Merged
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR improves Homebrew’s batch install/upgrade/reinstall resilience by ensuring that individual package failures (e.g., bottle extraction or download issues) are reported but do not abort the remainder of the run, while still exiting non-zero when any failures occurred.
Changes:
- Continue batch
brew upgrade, multi-formulabrew install, andbrew reinstallafter per-formula/cask failures instead of aborting the entire run. - Add retry behavior for bottles that fail to extract due to a corrupt cached download (rehash after failure, discard if mismatched, redownload once).
- Replace
DownloadQueue#fetch_failedwithfailed_downloadstracking to scope “distrust prefetch” behavior to only the package type that actually failed.
Reviewed changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| Library/Homebrew/upgrade.rb | Ensures a single formula upgrade failure doesn’t abort subsequent upgrades. |
| Library/Homebrew/install.rb | Skips installing only formulae whose downloads failed; continues other installs; tolerates per-formula install failures. |
| Library/Homebrew/bottle.rb | Adds post-extraction-failure checksum verification and a single redownload retry for corrupt cached bottles. |
| Library/Homebrew/formula_installer.rb | Uses Bottle#stage (with corrupt-cache retry) when pouring bottles outside the download-queue extraction path. |
| Library/Homebrew/download_queue.rb | Tracks failed_downloads instead of a single boolean, enabling finer-grained retry/skip decisions. |
| Library/Homebrew/cmd/upgrade.rb | Re-does unprefetched fetch only for the package type that actually failed in shared prefetch. |
| Library/Homebrew/cmd/reinstall.rb | Continues reinstalling remaining formulae after failures; skips only those whose downloads failed. |
| Library/Homebrew/cmd/install.rb | Continues installing remaining formulae/casks after individual failures; skips only formulae whose downloads failed. |
| Library/Homebrew/cask/reinstall.rb | Avoids aborting cask reinstall due to earlier failures in the same run. |
| Library/Homebrew/test/upgrade_spec.rb | Adds coverage that upgrade reports failure without aborting the batch. |
| Library/Homebrew/test/install_spec.rb | Adds coverage for skipping only failed-download formulae and continuing installs after an install failure. |
| Library/Homebrew/test/formula_installer_bottle_spec.rb | Adds coverage for corrupt cached bottle handling during install. |
| Library/Homebrew/test/download_queue_spec.rb | Updates expectations to validate failed_downloads behavior. |
| Library/Homebrew/test/cmd/upgrade_spec.rb | Updates queue doubles and adds coverage for scoped distrust of shared prefetch failures. |
| Library/Homebrew/test/cmd/reinstall_spec.rb | Adds coverage for continuing reinstall after one formula fails. |
| Library/Homebrew/test/cmd/install_spec.rb | Adds coverage ensuring installs proceed after earlier failures and updates queue doubles. |
| Library/Homebrew/test/cask/reinstall_spec.rb | Adds coverage that cask reinstall continues after earlier failures in the run. |
| Library/Homebrew/test/bottle_spec.rb | Adds unit coverage for corrupt cached bottle redownload retry vs. checksum-matching failures. |
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
- A bottle that fails to extract aborted the whole `brew upgrade` (or multi-formula `brew install`) run, so every remaining formula and cask was skipped: report the failure and carry on with the rest instead, still exiting nonzero. - `Bottle#downloaded_and_valid?` trusts an immutable GitHub Packages blob without rehashing it, so a corrupt cached bottle failed to extract on every run. Verify it after a failed extraction, then discard it and retry the extraction with a fresh download. - `brew install` and `brew reinstall` exited as soon as anything had failed, before installing anything at all: install what did download instead, skipping only the packages whose downloads failed. - Isolate each cask in `brew install` and each formula in `brew reinstall`, and widen the errors tolerated per package, so one failure no longer skips everything after it. - Report each cask failure as it happens with `ofail`, naming the cask, rather than collecting them into a `MultipleCaskErrors` raised once the batch is over: cask failures now read the same as formula ones. - Track which downloads failed in `DownloadQueue` so a failed bottle only distrusts the shared formula prefetch, rather than also making every already downloaded cask be fetched and verified again. Fixes #23519.
MikeMcQuaid
force-pushed
the
isolate-batch-install-failures
branch
from
August 14, 2026 16:21
be5f44a to
bd463ee
Compare
Contributor
|
Thanks Mike |
Member
Author
|
@joshka you're welcome, thanks for the good bug report. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
brew upgrade(or multi-formulabrew install) run, so every remaining formula and cask was skipped: report the failure and carry on with the rest instead, still exiting nonzero.Bottle#downloaded_and_valid?trusts an immutable GitHub Packages blob without rehashing it, so a corrupt cached bottle failed to extract on every run. Verify it after a failed extraction, then discard it and retry the extraction with a fresh download.brew installandbrew reinstallexited as soon as anything had failed, before installing anything at all: install what did download instead, skipping only the packages whose downloads failed.brew installand each formula inbrew reinstall, and widen the errors tolerated per package, so one failure no longer skips everything after it.DownloadQueueso a failed bottle only distrusts the shared formula prefetch, rather than also making every already downloaded cask be fetched and verified again.Fixes #23519.
brewcommands to reproduce the bug?brew lgtm(style, typechecking and tests) locally?Claude Opus 5 high with local review and testing.