Fix brew bundle topological sort crash on missing dependency node#22803
Merged
Conversation
Topo#tsort_each_child did an unguarded fetch on the dependency edge target, raising KeyError when an edge pointed at a formula absent from the node set (e.g. an installed keg that failed to load). Default a missing node to a leaf and drop the incidental .downcase, matching the defensive pattern used elsewhere in this file.
Contributor
There was a problem hiding this comment.
Pull request overview
Fixes a brew bundle crash during dependency topological sorting when a dependency edge references a formula that is not present in the Topo node set (previously raising KeyError from fetch).
Changes:
- Make
Homebrew::Bundle::Brew::Topo#tsort_each_childtreat missing nodes as leaves by defaulting to an empty child list. - Remove the
.downcaselookup transformation (keys/nodes are already stored and passed in the correct canonical form). - Add a unit spec asserting
Topo#tsortdoes not raise when an edge targets a missing node key.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
Library/Homebrew/bundle/brew.rb |
Prevents KeyError in Topo#tsort_each_child by defaulting missing nodes to [] (leaf behavior). |
Library/Homebrew/test/bundle/brew_spec.rb |
Adds a regression test covering an edge that points to a node without a corresponding key. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
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.
Fixes a
brew bundlecrash on Linux where the dependency topological sort dies withkey not found: "libice"(or another library name).Topo#tsort_each_childfetched a node's children with an unguardedfetch(node.downcase). That raisesKeyErrorwhenever a dependency edge points at a formula that is not in the node set. Nodes come from installed formulae, where kegs that fail to load are silently dropped. Edges come fromformulae_by_nameloaded from the tap or API. The two sources can disagree, so an edge target can have no matching key and the sort blows up instead of completing.The fix defaults a missing node to a leaf (no children), matching the existing defensive pattern at
formula_dep_names(find_formula(name)&.fetch(:dependencies, []) || []). I also dropped the.downcase: theTopokeys are stored verbatim from each formula'sname/full_name, and the node passed in is always one of those exact strings, so.downcasecould only ever break a lookup, never enable one. It was incidental dead code.Tests
Added a unit spec for
Homebrew::Bundle::Brew::Topo: build a graph whose edge references a node with no key of its own, then assert.tsortreturns the present nodes in dependency order without raising. Verified red/green with--only=bundle/brew(the example raisesKeyErrorbefore the change, passes after).Reproduction
This triggers when an installed keg fails to load and is dropped from the node set while still appearing as a dependency edge of another formula. On an affected Linux machine:
crashes in the sort with
key not found: "<library>". After this change the sort completes.I reproduced this in GitHub Actions CI and am hitting it deterministically:
https://github.com/bendrucker/dotfiles/actions/runs/27803390575/job/82279728443
brewcommands to reproduce the bug?brew lgtm(style, typechecking and tests) locally?AI was used to aid in diagnosing the crash and drafting the fix and test. I reviewed all of the code in detail before opening this PR. Tool: Claude Code (Opus 4.8).