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

  1. Delete the blob file named in the error — the CAS is content-addressed and will repopulate it on demand
  2. If corruption is widespread, remove the whole cache root and let it refill
  3. Stop external tools (sync clients, editors, AV) from writing into the cache directory
  4. 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

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


AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17). Data as JSON: /api/errors/493b50a67eababe2. Report an issue: GitHub.