caskroom: filter out casks without valid installation metadata#21630
Conversation
`Caskroom.casks` enumerates all directories in the Caskroom path but doesn't verify each cask is actually installed. When a cask directory exists but its `.metadata` directory is missing or corrupt, `installed_version` returns `nil`, causing `brew info --installed --json=v2` to include casks with `installed: null`. Add `.select(&:installed?)` to filter out these ghost entries so the method only returns genuinely installed casks, matching its documented behaviour of "Get all installed casks". Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
MikeMcQuaid
left a comment
There was a problem hiding this comment.
Thanks @koddsson! Not sure yet this is the ideal fix. What is the expected/necessary installation metadata that's missing in this case? Would be nice if we can infer it as it does seem in this case that the cask is still actually installed, we just can't detect it properly.
Similarly: any idea how casks end up in this state?
|
(I used a LLM to help me explore the code and keep the thoughts and ideas in order as well as helping me convey my thoughts in the most concise way) What metadata is missing?The expected on-disk structure for a properly installed cask is: The
Notably, Homebrew itself already treats these casks as not installed — running How do casks end up in this state?Honestly, I'm not fully sure. I've got roughly 80 affected casks across dozens of devices in my fleet, which suggests something more systemic than a one-off interrupted install. Some possibilities:
This is worth investigating further separately, but regardless of the root cause, these casks are in a state where Homebrew already considers them not installed. Can we infer the metadata instead?In principle, yes — we could infer the version from the version subdirectory name (e.g. I think the safer approach is to filter now (making I'm happy to be told I'm wrong on this inference if there's stuff about it that I'm missing. Maybe it's a lot easier than I think 😄 ReproductionI reproduced this locally by creating a bare Caskroom directory for a real cask token (e.g. One of the Workbrew engineers has this issue on their Device and I'm planning on jumping on a call with them later today and take a look together at their Caskroom to see if it's a permissions issue or something different. I'll make sure to report back here with our findings. |
Good enough for me, thanks! |
Summary
Caskroom.casksnow filters results with.select(&:installed?)to exclude cask directories that lack valid.metadata, preventingbrew info --installed --json=v2from returning casks withinstalled: nullinstalled_dependents_spec.rbtest to properly create.metadatadirectory structure so test casks are recognized as installedMotivation
When a cask directory exists in the Caskroom (e.g.
/opt/homebrew/Caskroom/arq/) but its.metadatadirectory is missing or corrupt,Caskroom.casksstill includes it. This causesbrew info --installed --json=v2to output casks with"installed": null, which breaks tooling that parses the JSON output.The fix adds
.select(&:installed?)after thefilter_mapblock inCaskroom.casks, which checks for a validinstalled_caskfile— the same conditioninstalled_versionrelies on. This matches the method's documented purpose of "Get all installed casks".Test plan
brew typecheckpassesbrew style --fix Library/Homebrew/cask/caskroom.rb Library/Homebrew/test/installed_dependents_spec.rb— no offensesbrew tests --only=installed_dependents— all 13 specs passbrew tests --only=cmd/--caskroom— all specs pass🤖 Generated with Claude Code