jdx/mise · error
brew-cask:{}: cask metadata has no sha256
Error message
brew-cask:{}: cask metadata has no sha256 What it means
fetch_archive (src/system/packages/brew/cask.rs:1049) enforces download integrity: after fetching the cask artifact it verifies the sha256 from the cask metadata, honoring the explicit 'no_check' opt-out. If the cask JSON carries no sha256 stanza at all, mise refuses to install an unverified download rather than skip integrity checking by default.
Source
Thrown at src/system/packages/brew/cask.rs:1049
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)
}
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())
.unwrap_or_default();
if is_dmg_archive(archive, filename)? {
file::un_dmg(archive, &extract_dir)?;
} else {View on GitHub (pinned to 6f52dcdf99)
Solutions
- If you maintain the tap, add the sha256 stanza to the cask (compute with shasum -a 256 on the artifact), or set it explicitly to no_check if the download genuinely changes per fetch (installer stubs)
- Prefer the official homebrew/cask build of the app when one exists
- Do not work around by disabling verification — the guard protects against tampered or corrupted downloads
Example fix
// before (tap's api/cask/myapp.json)
{ "token": "myapp", "version": "1.0", "url": "https://vendor/myapp.dmg" }
// after
{ "token": "myapp", "version": "1.0", "url": "https://vendor/myapp.dmg", "sha256": "<64-hex digest>" } Defensive patterns
Strategy: validation
Validate before calling
let cask = fetch_cask_json(token).await?;
match cask.sha256.as_deref() {
Some(_) | Some("no_check") => { /* proceed to install */ }
None => return Err(anyhow!("cask {token} ships no sha256 - refusing to install")),
} Prevention
- Only use taps whose cask JSON carries sha256 (or an explicit no_check for stub installers)
- Treat missing checksums in third-party taps as a supply-chain red flag
- When authoring internal casks, always compute and embed shasum -a 256 of the artifact
When it happens
Trigger: Installing a tapped cask whose api/cask/<token>.json omits the sha256 field. Official homebrew/cask metadata always carries sha256 or 'no_check', so this almost always comes from third-party or internal taps with hand-authored cask JSON.
Common situations: Internal taps generated by scripts that drop empty fields; quickly authored casks without checksums; repackaged vendor binaries where the packager skipped the shasum step.
Related errors
- Checksum mismatch for file {}: Expected: {algo}:{checksum} A
- {name}: sha256 is {actual}, the packslip says {}
- recovery content failed verification
- signed mise release checksum manifest contains an invalid SH
- brew-cask: invalid {kind} '{value}'
AI-assisted analysis of jdx/mise@6f52dcdf99 (2026-08-22).
Data as JSON: /api/errors/1b0f78f3c3a0994d.
Report an issue: GitHub.