Skip to content

Fix brew bundle topological sort crash on missing dependency node#22803

Merged
MikeMcQuaid merged 1 commit into
Homebrew:mainfrom
bendrucker:topo-sort-err
Jun 19, 2026
Merged

Fix brew bundle topological sort crash on missing dependency node#22803
MikeMcQuaid merged 1 commit into
Homebrew:mainfrom
bendrucker:topo-sort-err

Conversation

@bendrucker

@bendrucker bendrucker commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Fixes a brew bundle crash on Linux where the dependency topological sort dies with key not found: "libice" (or another library name).

Topo#tsort_each_child fetched a node's children with an unguarded fetch(node.downcase). That raises KeyError whenever 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 from formulae_by_name loaded 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: the Topo keys are stored verbatim from each formula's name/full_name, and the node passed in is always one of those exact strings, so .downcase could 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 .tsort returns the present nodes in dependency order without raising. Verified red/green with --only=bundle/brew (the example raises KeyError before 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:

brew bundle dump

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


  • Have you followed our Contributing guidelines?
  • Have you checked for other open Pull Requests for the same change?
  • Have you explained what your changes do?
  • Have you explained why you'd like these changes included, not just what they do?
  • For bug fixes, have you given step-by-step brew commands to reproduce the bug?
  • Have you written new tests (excluding integration tests)?
  • Have you successfully run brew lgtm (style, typechecking and tests) locally?

  • AI was used to generate or assist with generating this PR.

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).

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.
Copilot AI review requested due to automatic review settings June 19, 2026 04:58

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_child treat missing nodes as leaves by defaulting to an empty child list.
  • Remove the .downcase lookup transformation (keys/nodes are already stored and passed in the correct canonical form).
  • Add a unit spec asserting Topo#tsort does 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.

@MikeMcQuaid MikeMcQuaid left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@MikeMcQuaid MikeMcQuaid added this pull request to the merge queue Jun 19, 2026
Merged via the queue into Homebrew:main with commit b98ad43 Jun 19, 2026
44 of 50 checks passed
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.

3 participants