jdx/mise · error
packslip:{project}@{version}: manifest digest differs from s
Error message
packslip:{project}@{version}: manifest digest differs from signed list What it means
During version discovery, mise computes the SHA-256 digest of a downloaded packslip manifest and compares it against every pinned digest — the vendor's signed release list and optionally the mise.lock stamp. If the actual digest differs from ANY pinned digest, install is refused because the manifest is not the artifact that the signing party reviewed. This guards against a swapped or tampered manifest between discovery and install.
Source
Thrown at src/backend/packslip.rs:851
),
None => {
let vendor = self.locate_bundle(project, &tv, pin, opts).await?;
(vendor.url, vendor.digest)
}
};
let url = url.as_str();
let text = HTTP_FETCH
.get_text_request(url)
.headers(&headers_for(url)?)
.send()
.await?;
let actual = hex::encode(Sha256::digest(text.as_bytes()));
for expected in vendor_digest
.iter()
.chain(stamp.and_then(|s| s.digest.as_ref()))
{
if &actual != expected {
bail!("packslip:{project}@{version}: manifest digest differs from signed list");
}
}
let verified = verify_bundle(&text, pin, !opts.allow_unlogged(), &[])?;
if verified.project != project || verified.version != version {
bail!(
"packslip:{project}@{version}: verified manifest project/version differs from discovery"
);
}
let scheme = verified.scheme.to_string();
let attested_by = verified.attested_by.to_string();
packslip_pins::check(
project,
Observed {
scheme: &scheme,
key_id: &verified.key_id,
issuer: verified.issuer.as_deref(),
attested_by: &attested_by,
provenance: verified.provenance_linked,View on GitHub (pinned to afd2eddd3a)
Solutions
- Clear the cached manifest and re-run the discovery/install so a fresh copy is fetched
- Remove the stale stamp digest entry from mise.lock (and re-trust the current release)
- Re-run `mise ls-remote packslip:<project>` to refresh the vendor's signed release list
- Verify the vendor's release page for notice of a re-signed manifest before bypassing anything
Example fix
// before (mise.lock) [[tools.node.platforms.linux-x64]] stamp.digest = "old-digest-hex" // after # remove the stamp.digest entry or update it to the digest published in the vendor's signed release list
Defensive patterns
Strategy: validation
Validate before calling
use sha2::{Digest, Sha256};
fn manifest_matches_pinned(manifest_bytes: &[u8], pinned: &[String]) -> bool {
let actual = hex::encode(Sha256::digest(manifest_bytes));
pinned.iter().any(|p| p.eq_ignore_ascii_case(&actual))
} Prevention
- Don't hand-edit mise.lock stamp digests; let mise write them
- After a vendor re-signs a release, refresh the lock entry instead of keeping the old digest
- Keep caches clean on CI so stale manifests aren't reused
When it happens
Trigger: Calling latest_version_with_selection_options (candidate_exclusion phase) for a packslip: backend tool when the downloaded manifest bytes hash to a value that does not equal one of the digests in vendor_digest or the stamp's digest — e.g. the upstream release list was updated, the manifest was regenerated/re-signed, or the cache served a stale file.
Common situations: A vendor re-published a release with an amended manifest; mise.lock pins an old stamp digest while the vendor list moved on; a proxy or CDN served a different manifest; you edited a packslip manifest locally for testing.
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
- the packslip at {} is not the one the signed release list po
- {name}: sha256 is {actual}, the packslip says {}
- brew-cask:{}: cask metadata has no sha256
- the packslip names an executable {:?}, which is not a plain
- the packslip lists executable {} in {}, but the archive hold
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/3f7b7e9ab83fdd43.
Report an issue: GitHub.