{"record":{"id":"e21204af92282436","repo":"jdx/mise","slug":"brew-cask-cask-metadata-has-no-sha256-e21204","errorCode":null,"errorMessage":"brew-cask:{}: cask metadata has no sha256","messagePattern":"brew-cask:(.+?): cask metadata has no sha256","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/cask/fetch.rs","lineNumber":258,"sourceCode":"    let url_hash = &hash::hash_sha256_to_str(&cask.url)[..12];\n    let archive = cache_dir.join(format!(\n        \"{}-{}-{url_hash}-{filename}\",\n        cask.token, cask.version\n    ));\n    if !archive.exists() {\n        HTTP.download_file(&cask.url, &archive, pr).await?;\n        // Strip macOS quarantine so it doesn't propagate into extracted/copied artifacts.\n        let _ = std::process::Command::new(\"xattr\")\n            .args([\"-d\", \"com.apple.quarantine\"])\n            .arg(&archive)\n            .stdout(std::process::Stdio::null())\n            .stderr(std::process::Stdio::null())\n            .status();\n    }\n    match cask.sha256.as_deref() {\n        Some(\"no_check\") => {}\n        Some(sha256) => hash::ensure_checksum(&archive, sha256, pr, \"sha256\")?,\n        None => bail!(\"brew-cask:{}: cask metadata has no sha256\", cask.token),\n    }\n    Ok(archive)\n}\n\npub(super) fn extract_archive(\n    cask: &Cask,\n    archive: &Path,\n    pr: Option<&dyn SingleReport>,\n) -> Result<PathBuf> {\n    let extract_dir = crate::dirs::CACHE\n        .join(\"system-brew\")\n        .join(\"cask-extract\")\n        .join(format!(\"{}-{}\", cask.token, cask.version));\n    file::remove_all(&extract_dir)?;\n    file::create_dir_all(&extract_dir)?;\n    let filename = archive\n        .file_name()\n        .and_then(|f| f.to_str())","sourceCodeStart":240,"sourceCodeEnd":276,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/packages/brew/cask/fetch.rs#L240-L276","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Add the correct sha256 digest to the cask metadata (compute with `shasum -a 256 <file>` on the official artifact).","If upstream genuinely publishes no checksum, set sha256 to the literal string 'no_check' to opt out explicitly — understanding verification is then skipped.","Refresh the cask metadata from the official Homebrew API, which always supplies sha256, rather than a partial tap copy."],"exampleFix":"// before\n{\"token\": \"myapp\", \"url\": \"https://example.com/myapp.zip\"}\n// after\n{\"token\": \"myapp\", \"url\": \"https://example.com/myapp.zip\", \"sha256\": \"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08\"}","handlingStrategy":"validation","validationCode":"// verify cask JSON carries a checksum before installing\nconst meta = JSON.parse(fs.readFileSync(caskJson, 'utf8'));\nif (!meta.sha256) throw new Error(`cask ${meta.token} missing sha256`);","typeGuard":"function hasSha256(c) { return typeof c.sha256 === 'string' && c.sha256.length > 0; }","tryCatchPattern":null,"preventionTips":["Always include sha256 (or explicit 'no_check') in hand-written cask JSON.","Compute the digest with `shasum -a 256` on the exact published artifact.","Prefer official-API cask metadata over partial tap copies."],"tags":["brew","checksum","integrity","package-install"],"backgroundTag":"checksum-mismatch","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}