jdx/mise · error

brew-cask: : cask metadata has no sha256

Error message

brew-cask:{}: cask metadata has no sha256

What it means

Every downloaded cask archive must be verified against a sha256 checksum. `fetch_archive` accepts the special value "no_check" (explicit opt-out), a real digest (verified via hash::ensure_checksum), or — if the cask JSON has no sha256 field at all — throws this error. A missing digest means the cask metadata is incomplete and the download cannot be proven intact, so the fetch refuses to proceed.

Solutions

  1. Add a sha256 digest to the cask's url stanza in the tap (sha256 of the downloaded artifact)
  2. Set sha256 to "no_check" explicitly if verification is intentionally skipped
  3. Re-fetch cask metadata in case the JSON was truncated or parsed incorrectly

Example fix

// before (cask url stanza)
url "https://example.com/foo.zip"
// after
url "https://example.com/foo.zip"
sha256 "9a1f...c3"
Defensive patterns

Strategy: validation

Validate before calling

// Check cask metadata for a checksum before downloading
match cask.sha256.as_deref() {
    Some("no_check") => {},
    Some(sha) if sha.len() == 64 && sha.chars().all(|c| c.is_ascii_hexdigit()) => {},
    _ => eprintln!("cask metadata must include a sha256 (or explicit \"no_check\")"),
}

Prevention

When it happens

Trigger: fetch_archive (from fetch_and_stage or prewarm_downloads) processes a Cask whose `sha256` field is None — the API/tap JSON omitted the sha256 key for the archive stanza.

Common situations: A tap publishes a cask without a sha256 in its url stanza; a parsing bug or schema change drops the sha256 field from the fetched JSON; a hand-written cask JSON missing the checksum.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/e21204af92282436. Report an issue: GitHub.

Appendix: source

Thrown at src/system/packages/brew/cask/fetch.rs:254

    let url_hash = &hash::hash_sha256_to_str(&cask.url)[..12];
    let archive = cache_dir.join(format!(
        "{}-{}-{url_hash}-{filename}",
        cask.token, cask.version
    ));
    if !archive.exists() {
        HTTP.download_file(&cask.url, &archive, pr).await?;
        // Strip macOS quarantine so it doesn't propagate into extracted/copied artifacts.
        let _ = std::process::Command::new("xattr")
            .args(["-d", "com.apple.quarantine"])
            .arg(&archive)
            .stdout(std::process::Stdio::null())
            .stderr(std::process::Stdio::null())
            .status();
    }
    match cask.sha256.as_deref() {
        Some("no_check") => {}
        Some(sha256) => hash::ensure_checksum(&archive, sha256, pr, "sha256")?,
        None => bail!("brew-cask:{}: cask metadata has no sha256", cask.token),
    }
    Ok(archive)
}

pub(super) fn extract_archive(
    cask: &Cask,
    archive: &Path,
    pr: Option<&dyn SingleReport>,
) -> Result<PathBuf> {
    let extract_dir = crate::dirs::CACHE
        .join("system-brew")
        .join("cask-extract")
        .join(format!("{}-{}", cask.token, cask.version));
    file::remove_all(&extract_dir)?;
    file::create_dir_all(&extract_dir)?;
    let filename = archive
        .file_name()
        .and_then(|f| f.to_str())

View on GitHub (pinned to 533346cc37)