jdx/mise · error · RuntimeError

cask has no version

Error message

cask has no version

What it means

`tap_cask_metadata.rb` parses a cask file in a minimal sandboxed DSL and collects fields into a hash via `to_h`. A cask without a `version` stanza is incomplete/invalid, so `to_h` raises 'cask has no version' rather than emitting a hash with a null version. This guards the metadata generation pipeline from publishing unusable cask records.

Source

Thrown at src/system/packages/brew/tap_cask_metadata.rb:250

    when :or_older then host <= target || host.same_release?(target)
    when :or_newer then host >= target
    else host.same_release?(target)
    end
  end
  private :macos_condition_matches?

  def name(*) = nil
  def desc(*) = nil
  def homepage(*) = nil
  def livecheck(*) = nil
  def caveats(*) = nil
  def container(*) = nil
  def deprecate!(**) = nil
  def disable!(**) = nil
  def no_autobump!(*) = nil

  def to_h
    raise "cask has no version" if @version.nil?
    raise "cask has no URL" if @url.to_s.empty?
    {
      "token" => @token,
      "version" => @version.to_s,
      "auto_updates" => @auto_updates,
      "url" => @url,
      "sha256" => @sha256,
      "artifacts" => @artifacts,
      "depends_on" => {
        "formula" => @formula_dependencies,
        "cask" => @cask_dependencies
      },
      "conflicts_with" => { "cask" => @conflicting_casks },
      "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")
    }
  end

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Add a `version "..."` stanza to the cask file being evaluated
  2. Verify the cask file passed via stdin is complete and not truncated
  3. Check the version stanza uses DSL the shim implements (e.g. plain `version`); unimplemented DSL raises separately or is dropped
  4. Ensure the correct CASK_FILE/token env is set so the intended cask (not an empty stub) is parsed

Example fix

# before (cask body)
cask 'mytool' do
  url 'https://example.com/mytool.zip'
end
# after
cask 'mytool' do
  version '1.2.3'
  url 'https://example.com/mytool-1.2.3.zip'
end
Defensive patterns

Strategy: validation

Validate before calling

raise 'cask file missing version stanza' unless File.read(cask_path).match?(/^\s*version\s+/)
metadata = eval_cask(cask_path)
metadata.to_h

Type guard

valid = m.respond_to?(:to_h) && !m.instance_variable_get(:@version).nil?

Try / catch

begin
  hash = metadata.to_h
rescue RuntimeError => e
  raise unless e.message == 'cask has no version'
  # skip/flag cask as incomplete
end

Prevention

When it happens

Trigger: `to_h` is called on a `CaskMetadata` instance whose `@version` is still nil — i.e. the evaluated cask block never called `version ...`, or the DSL stub ignored/failed to record it before `to_h` runs at the end of the eval script.

Common situations: Hand-written or truncated cask files missing the `version` stanza; a cask DSL token the metadata shim doesn't implement causing the version line to be swallowed; copy-pasting a template cask without filling in version; upstream renamed/obsoleted the version stanza style.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/80d228191db4dcac. Report an issue: GitHub.