jdx/mise · error

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

Error message

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

What it means

Every archive-backed cask must carry a sha256 for integrity verification. After downloading, mise matches on the cask's sha256 field: 'no_check' skips verification, a hex digest is verified, and an absent value is a hard error — mise refuses to install unverified archives. This protects against installing tampered or truncated downloads when cask metadata is incomplete.

Source

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

    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 afd2eddd3a)

Solutions

  1. Add the correct sha256 digest to the cask metadata (compute with `shasum -a 256 <file>` on the official artifact).
  2. If upstream genuinely publishes no checksum, set sha256 to the literal string 'no_check' to opt out explicitly — understanding verification is then skipped.
  3. Refresh the cask metadata from the official Homebrew API, which always supplies sha256, rather than a partial tap copy.

Example fix

// before
{"token": "myapp", "url": "https://example.com/myapp.zip"}
// after
{"token": "myapp", "url": "https://example.com/myapp.zip", "sha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"}
Defensive patterns

Strategy: validation

Validate before calling

// verify cask JSON carries a checksum before installing
const meta = JSON.parse(fs.readFileSync(caskJson, 'utf8'));
if (!meta.sha256) throw new Error(`cask ${meta.token} missing sha256`);

Type guard

function hasSha256(c) { return typeof c.sha256 === 'string' && c.sha256.length > 0; }

Prevention

When it happens

Trigger: fetch_archive is called (via fetch_and_stage) for a cask whose metadata JSON has no sha256 key and whose URL is not a git URL; i.e. any archive cask installed from metadata lacking a checksum.

Common situations: Third-party taps with hand-written cask JSON missing the sha256 field; locally modified cask metadata where the checksum was deleted; tooling that regenerated cask JSON and dropped 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@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/e21204af92282436. Report an issue: GitHub.