{"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":254,"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":236,"sourceCodeEnd":272,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/packages/brew/cask/fetch.rs#L236-L272","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Add a sha256 digest to the cask's url stanza in the tap (sha256 of the downloaded artifact)","Set sha256 to \"no_check\" explicitly if verification is intentionally skipped","Re-fetch cask metadata in case the JSON was truncated or parsed incorrectly"],"exampleFix":"// before (cask url stanza)\nurl \"https://example.com/foo.zip\"\n// after\nurl \"https://example.com/foo.zip\"\nsha256 \"9a1f...c3\"","handlingStrategy":"validation","validationCode":"// Check cask metadata for a checksum before downloading\nmatch cask.sha256.as_deref() {\n    Some(\"no_check\") => {},\n    Some(sha) if sha.len() == 64 && sha.chars().all(|c| c.is_ascii_hexdigit()) => {},\n    _ => eprintln!(\"cask metadata must include a sha256 (or explicit \\\"no_check\\\")\"),\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always include sha256 in cask url stanzas","Use \"no_check\" explicitly rather than omitting the field when skipping verification","Re-sync cask metadata if fetched JSON appears truncated"],"tags":["homebrew","cask","checksum","missing-metadata"],"backgroundTag":"checksum-mismatch","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}