jdx/mise · error · RuntimeError
no Formula subclass found
Error message
no Formula subclass found
What it means
mise's formula metadata extractor evals a Homebrew formula DSL file and expects that evaluating it defines a subclass of the stub `Formula` class (via Homebrew's `class Foo < Formula` pattern, captured in `Formula.inherited`). If the evaluated file never defines a Formula subclass, `Formula.instance_variable_get(:@subclass)` is nil and this raise fires. This means the file on STDIN is not a recognizable Homebrew formula.
Source
Thrown at src/system/packages/brew/tap_formula_metadata.rb:216
def bottle(*) = nil
def head(*) = nil
def livecheck(*) = nil
def service(*) = nil
def test(*) = nil
def method_missing(*) = nil
def respond_to_missing?(*) = true
end
end
def inferred_version(url)
basename = File.basename(url.to_s).sub(/\.(tar\.(gz|xz|bz2|zst)|tgz|txz|zip|gz)\z/i, "")
match = basename.match(/(?:^|[-_v])([0-9]+(?:\.[0-9A-Za-z]+)+(?:[-_.][0-9A-Za-z]+)*)/)
match && match[1]
end
eval(STDIN.read.force_encoding("UTF-8"), TOPLEVEL_BINDING, FORMULA_FILE, 1)
klass = Formula.instance_variable_get(:@subclass)
raise "no Formula subclass found" unless klass
raise "formula has no stable URL" if klass.source_url.to_s.empty?
raise "formula has no stable sha256" if klass.source_sha256.to_s.empty?
version = (klass.explicit_version || inferred_version(klass.source_url)).to_s
raise "could not infer formula version; add an explicit version declaration" if version.to_s.empty?
metadata = {
"name" => FORMULA_NAME,
"tap" => ENV.fetch("MISE_BREW_TAP"),
"versions" => { "stable" => version },
"revision" => klass.revision_value || 0,
"keg_only" => klass.keg_only_value || false,
"dependencies" => klass.runtime_dependencies || [],
"build_dependencies" => klass.build_dependencies || [],
"bottle" => {},
"urls" => { "stable" => { "url" => klass.source_url, "checksum" => klass.source_sha256 } },
"ruby_source_path" => ENV.fetch("MISE_BREW_SOURCE_PATH"),
"ruby_source_checksum" => { "sha256" => ENV.fetch("MISE_BREW_SOURCE_CHECKSUM") },
"tap_git_head" => ENV.fetch("MISE_BREW_TAP_COMMIT")View on GitHub (pinned to afd2eddd3a)
Solutions
- Check that MISE_BREW_SOURCE_PATH points at an actual Homebrew formula Ruby file containing `class X < Formula`
- Inspect the file content — if it's an HTML error page or empty, fix the source URL/fetch that produced it and re-fetch the tap
- Verify the formula name/path in the tap (file names differ from formula tokens; e.g. python@3.12 lives at Formula/python@3.12.rb)
- Re-clone/refresh the tap so the file is intact
Example fix
// before: file content piped to the extractor // <html><body>404 Not Found</body></html> // after: pipe the real formula file // class Wget < Formula // url "https://ftp.gnu.org/gnu/wget/wget-1.25.0.tar.gz" // sha256 "..." // end
Defensive patterns
Strategy: validation
Validate before calling
content = File.read(formula_path)
raise "#{formula_path} is not a formula file" unless content.match?(/^\s*class\s+\w+\s*<\s*Formula\b/) Type guard
def formula_file?(path) content = (File.read(path) rescue nil) || "" content.match?(/^\s*class\s+\w+\s*<\s*Formula\b/) end
Try / catch
begin
extract_formula_metadata(formula_path)
rescue RuntimeError => e
raise unless e.message == "no Formula subclass found"
warn "#{formula_path} does not define a Formula subclass; check tap path and fetch"
end Prevention
- Validate MISE_BREW_SOURCE_PATH exists and starts with `class ... < Formula` before piping it to the extractor
- Check for HTML error pages / empty files when fetching formula sources from taps
- Match formula token to file path carefully (Formula/<name>.rb, including @version suffixes)
- Re-clone the tap if the checkout appears truncated or corrupted
When it happens
Trigger: Piping a file to src/system/packages/brew/tap_formula_metadata.rb that contains no `class Something < Formula` declaration — e.g. an empty file, an HTML error page, a 404 body, a cask file, or a non-Ruby file at MISE_BREW_SOURCE_PATH.
Common situations: The tap path for the formula is wrong so the fetch returned an error page or empty content; the file is a Cask or other Ruby file rather than a formula; tap checkout is broken/truncated; formula renamed and the file no longer exists at the expected path.
Related errors
- brew: tapped formula '{name}' needs a GitHub tap URL in [boo
- tap formula name mismatch: requested '{name}', extracted '{}
- invalid GitHub tap URL '{url}'
- tap repository tree was truncated
- tap {directory} directory tree was truncated
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/d42ced4437138288.
Report an issue: GitHub.