jdx/mise · error · RuntimeError

cask has no URL

Error message

cask has no URL

What it means

Same pipeline as the 'no version' guard: `to_h` in the cask metadata shim validates the collected fields and raises 'cask has no URL' when `@url` is empty. Every cask must declare at least one `url` stanza for the artifact download, so an empty URL means the parsed cask is incomplete and its metadata cannot be serialized.

Source

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

    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/restore a `url "..."` stanza in the cask file
  2. Confirm the url stanza is unconditional and uses arguments the shim's DSL accepts
  3. Re-fetch the cask file from the tap in case of a truncated download
  4. Check `MISE_BREW_TOKEN` matches the intended cask so the right file is evaluated

Example fix

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

Strategy: validation

Validate before calling

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

Type guard

valid = !metadata.instance_variable_get(:@url).to_s.empty?

Try / catch

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

Prevention

When it happens

Trigger: `to_h` runs on a `CaskMetadata` whose `url` stanza was never invoked (or was invoked with nil/empty) — cask file lacks `url`, or the `url` line failed to parse through the shim's DSL before serialization.

Common situations: Cask template missing the `url` stanza; a conditional/templated URL stanza the simple DSL parser doesn't execute; malformed url arguments causing the shim's `url` method not to record it; corrupted or partial cask file fetched from a tap.

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/18b35923ff04d1f5. Report an issue: GitHub.