jdx/mise · error · eyre::Report
local CAS blob failed digest verification: {}
Error message
local CAS blob failed digest verification: {} What it means
LocalCas::find re-hashes a CAS file that already exists at the expected path (<root>/cas/v1/<algorithm>/<hash[0..2]>/<hash>-<size>) and compares it to the digest before returning it. A mismatch means on-disk corruption: the store refuses to hand back data that no longer matches its content-addressed key, and the message names the offending path.
Source
Thrown at crates/mise-cache-core/src/local.rs:49
/// Resolve the storage path for a validated digest.
pub fn path_for(&self, digest: &CacheDigest) -> Result<PathBuf> {
digest.validate()?;
Ok(self
.root
.join("cas/v1")
.join(&digest.algorithm)
.join(&digest.hash[..2])
.join(format!("{}-{}", digest.hash, digest.size)))
}
/// Find and verify a stored object.
pub fn find(&self, digest: &CacheDigest) -> Result<Option<PathBuf>> {
let path = self.path_for(digest)?;
if !path.exists() {
return Ok(None);
}
if !digest.matches_file(&path)? {
bail!(
"local CAS blob failed digest verification: {}",
path.display()
);
}
Ok(Some(path))
}
/// Atomically store bytes after verifying their declared digest.
pub fn store_bytes(&self, digest: &CacheDigest, bytes: &[u8]) -> Result<PathBuf> {
if !digest.matches_bytes(bytes)? {
bail!("bytes do not match the declared CAS digest");
}
self.store_with(digest, |temporary| {
temporary.write_all(bytes)?;
Ok(())
})
}
View on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Delete the blob file named in the error — the CAS is content-addressed and will repopulate it on demand
- If corruption is widespread, remove the whole cache root and let it refill
- Stop external tools (sync clients, editors, AV) from writing into the cache directory
- Confirm the cache root is not shared between different cache formats or versions
Example fix
# before: cas.find(&digest) fails with # local CAS blob failed digest verification: /home/u/.cache/mise/cas/v1/blake3/ab/abcd1234…-42 # after: drop the corrupt blob (safe — it is content-addressed) and retry rm /home/u/.cache/mise/cas/v1/blake3/ab/abcd1234…-42
Defensive patterns
Strategy: fallback
Try / catch
let path = match cas.find(&digest) {
Ok(path) => path,
Err(report) if report.to_string().contains("digest verification") => {
// corrupt on-disk blob: drop it (content-addressed, will be repopulated) -> miss
let _ = std::fs::remove_file(cas.path_for(&digest)?);
None
}
Err(report) => return Err(report),
}; Prevention
- Keep the cache root excluded from sync clients, editors, and antivirus
- Do not share one cache root between different mise/cache versions
- Treat single-blob verification failures as misses and delete the named file
When it happens
Trigger: Anything mutating files under the CAS root after publication: disk corruption or bit rot, external processes editing cache files, a crash during a non-atomic write in an older version, or two cache layouts sharing one root.
Common situations: Users or cleanup tools writing inside the cache directory; failing disks; sharing a cache dir between mise versions with different layouts; antivirus or sync clients touching files; backup restores with altered metadata/content.
Related errors
- bytes do not match the declared CAS digest
- staged blob does not match the declared CAS digest
- staged blob size does not match the declared CAS digest
- local action result is invalid: {}
- unsupported remote cache digest algorithm
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/493b50a67eababe2.
Report an issue: GitHub.