{"record":{"id":"21ee3ff49aaa1a20","repo":"jdx/mise","slug":"the-stamp-for-packslip-project-from-records-no-sha256-for-so","errorCode":null,"errorMessage":"the stamp for packslip:{project}@{} from {} records no sha256 for {}, so nothing says the manifest is the one that host reviewed","messagePattern":"the stamp for packslip:(.+?)@(.+?) from (.+?) records no sha256 for (.+?), so nothing says the manifest is the one that host reviewed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/backend/packslip.rs","lineNumber":896,"sourceCode":"    /// any target platform, while latest-version selection uses the same policy\n    /// path to decide whether a candidate is eligible.\n    async fn verified_release(\n        &self,\n        project: &str,\n        tv: &ToolVersion,\n        pin: &Pin,\n        opts: &PackslipOptions<'_>,\n        stamp: Option<&crate::packslip_stamps::Stamp>,\n    ) -> Result<(Statement, packslip::Verified)> {\n        use sha2::{Digest, Sha256};\n\n        // With a stamp in hand the manifest is already named, so the vendor is\n        // asked only for withdrawals and its digest pin. Requiring the original\n        // release asset here would refuse a stamped mirror that install accepts.\n        let (url, vendor_digest) = match stamp {\n            Some(stamp) => {\n                if stamp.digest.is_none() {\n                    bail!(\n                        \"the stamp for packslip:{project}@{} from {} records no sha256 for {}, so nothing says the manifest is the one that host reviewed\",\n                        tv.version,\n                        stamp.host,\n                        stamp.entry.packslip\n                    );\n                }\n                (\n                    stamp.entry.packslip.clone(),\n                    self.vendor_entry(project, tv, pin, opts)\n                        .await?\n                        .and_then(|vendor| vendor.digest),\n                )\n            }\n            None => {\n                let vendor = self.locate_bundle(project, tv, pin, opts).await?;\n                (vendor.url, vendor.digest)\n            }\n        };","sourceCodeStart":878,"sourceCodeEnd":914,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/backend/packslip.rs#L878-L914","documentation":"A stamp (record of a host having reviewed a packslip manifest) exists but records no sha256 digest. Without the digest nothing ties the stamp's review claim to a specific file, so mise refuses to treat the stamped URL as reviewed content.","triggerScenarios":"verified_release (called from candidate_exclusion/resolve_lock_info) receives Some(stamp) whose stamp.digest is None while consulting the vendor for withdrawals and the digest pin.","commonSituations":"A mirror host generated a stamp without computing the manifest digest; a hand-written or tool-migrated stamp entry omits the digest field; the stamp format was extended and older stamps predate digests.","solutions":["Regenerate the stamp so it records the sha256 of the exact reviewed manifest","Remove the stamp so mise falls back to requiring the original vendor release asset","Fix whatever stamping host/tool wrote the digest-less stamp to include sha256"],"exampleFix":"null","handlingStrategy":"validation","validationCode":"// before accepting a stamp, require the digest field\nif let Some(stamp) = &stamp {\n    assert!(stamp.digest.is_some(), \"stamp must record sha256\");\n}","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Always emit the sha256 when generating stamps","Validate stamp files after any stamping-tool migration","Treat digest-less stamps as invalid at write time, not install time"],"tags":["packslip","stamp","sha256","integrity"],"backgroundTag":"missing-required-config-field","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"}