{"record":{"id":"18b35923ff04d1f5","repo":"jdx/mise","slug":"cask-has-no-url","errorCode":null,"errorMessage":"cask has no URL","messagePattern":"cask has no URL","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/tap_cask_metadata.rb","lineNumber":251,"sourceCode":"    when :or_newer then host >= target\n    else host.same_release?(target)\n    end\n  end\n  private :macos_condition_matches?\n\n  def name(*) = nil\n  def desc(*) = nil\n  def homepage(*) = nil\n  def livecheck(*) = nil\n  def caveats(*) = nil\n  def container(*) = nil\n  def deprecate!(**) = nil\n  def disable!(**) = nil\n  def no_autobump!(*) = nil\n\n  def to_h\n    raise \"cask has no version\" if @version.nil?\n    raise \"cask has no URL\" if @url.to_s.empty?\n    {\n      \"token\" => @token,\n      \"version\" => @version.to_s,\n      \"auto_updates\" => @auto_updates,\n      \"url\" => @url,\n      \"sha256\" => @sha256,\n      \"artifacts\" => @artifacts,\n      \"depends_on\" => {\n        \"formula\" => @formula_dependencies,\n        \"cask\" => @cask_dependencies\n      },\n      \"conflicts_with\" => { \"cask\" => @conflicting_casks },\n      \"ruby_source_path\" => ENV.fetch(\"MISE_BREW_SOURCE_PATH\"),\n      \"ruby_source_checksum\" => { \"sha256\" => ENV.fetch(\"MISE_BREW_SOURCE_CHECKSUM\") },\n      \"tap_git_head\" => ENV.fetch(\"MISE_BREW_TAP_COMMIT\")\n    }\n  end\n","sourceCodeStart":233,"sourceCodeEnd":269,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/packages/brew/tap_cask_metadata.rb#L233-L269","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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.","solutions":["Add/restore a `url \"...\"` stanza in the cask file","Confirm the url stanza is unconditional and uses arguments the shim's DSL accepts","Re-fetch the cask file from the tap in case of a truncated download","Check `MISE_BREW_TOKEN` matches the intended cask so the right file is evaluated"],"exampleFix":"# before\ncask 'mytool' do\n  version '1.2.3'\n  sha256 :no_check\nend\n# after\ncask 'mytool' do\n  version '1.2.3'\n  url 'https://example.com/mytool-1.2.3.zip'\n  sha256 :no_check\nend","handlingStrategy":"validation","validationCode":"raise 'cask file missing url stanza' unless File.read(cask_path).match?(/^\\s*url\\s+/)\nmetadata = eval_cask(cask_path)\nmetadata.to_h","typeGuard":"valid = !metadata.instance_variable_get(:@url).to_s.empty?\n","tryCatchPattern":"begin\n  hash = metadata.to_h\nrescue RuntimeError => e\n  raise unless e.message == 'cask has no URL'\n  # skip/flag cask as incomplete\nend","preventionTips":["Always include an unconditional url stanza in casks","Lint casks for required fields before extraction","Re-download cask files if extraction unexpectedly fails"],"tags":["ruby","homebrew-cask","metadata","validation"],"backgroundTag":"missing-required-config-field","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}