jdx/mise · error

local CAS blob failed digest verification

Error message

local CAS blob failed digest verification: {}

What it means

`LocalCas::find` located the file at its content-addressed path (`cas/v1/<algo>/<hash[0..2]>/<hash>-<size>`) but re-hashing the file no longer matches the digest encoded in the path. The CAS treats this as corruption: the blob is not returned and the error names the offending path. Because paths derive from digests, something must have mutated the file after it was stored.

Solutions

  1. Delete the offending blob named in the error (or the whole `cas/v1` subtree) - the next run recomputes and re-stores it.
  2. Run disk diagnostics (SMART, fsck) if corruption recurs.
  3. Ensure nothing outside mise writes into the cache root, and exclude it from antivirus/backup tools that rewrite files.
  4. In calling code, treat `find` errors as cache misses: recompute and `store_bytes` to heal the entry.

Example fix

// before: propagate the corruption error
let path = cas.find(&digest)?.unwrap();

// after: treat a corrupt blob as a miss and heal it
let path = match cas.find(&digest) {
    Ok(Some(path)) => path,
    _ => cas.store_bytes(&digest, &recompute())?,
};
Defensive patterns

Strategy: fallback

Try / catch

let path = match cas.find(&digest) {
    Ok(Some(path)) => path,
    Ok(None) => cas.store_bytes(&digest, &produce())?,
    Err(err) => {
        warn!("corrupt CAS blob, healing: {err}");
        cas.store_bytes(&digest, &produce())? // recompute and overwrite by re-storing
    }
};

Prevention

When it happens

Trigger: Any `find`/`store_file` call that hits a CAS entry whose on-disk contents were changed: another process (editor, antivirus, backup or cleanup tool, user) modified or truncated files under the cache root; bit rot or filesystem corruption; a foreign file placed at the digest path by a different cache layout or version.

Common situations: Hand-editing or sparse-truncating files under the cache root; failing disks; sharing one cache directory between incompatible tool versions; cleanup utilities that touch files they should not.

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


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

Appendix: 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 6f52dcdf99)