jdx/mise · error

bytes do not match the declared CAS digest

Error message

bytes do not match the declared CAS digest

What it means

`LocalCas::store_bytes` verifies the in-memory bytes against the declared digest (both size and hash, blake3 or sha-256) before writing anything to disk. A mismatch means the digest was computed over different bytes than the ones passed, and the store refuses to publish content that would corrupt the content-addressed layout.

Solutions

  1. Compute the digest from the exact same slice immediately before storing: `let digest = CacheDigest::blake3(&bytes); cas.store_bytes(&digest, &bytes)`.
  2. When the digest comes from a manifest or remote peer, call `digest.matches_bytes(&bytes)` first and handle a mismatch explicitly instead of storing.
  3. Check that `digest.size` is the byte length of the content, not a human-readable size.

Example fix

// before
let digest = CacheDigest::blake3(&original);
cas.store_bytes(&digest, &updated)?; // bails

// after
let digest = CacheDigest::blake3(&updated);
cas.store_bytes(&digest, &updated)?;
Defensive patterns

Strategy: validation

Validate before calling

if !digest.matches_bytes(&bytes)? {
    // digest describes different content: recompute it from these bytes
    let digest = CacheDigest::blake3(&bytes);
    return cas.store_bytes(&digest, bytes);
}
cas.store_bytes(&digest, &bytes)?;

Prevention

When it happens

Trigger: Hashing one buffer but storing another: computing `CacheDigest::blake3(&old_bytes)` then passing `new_bytes` to `store_bytes`; a digest deserialized from JSON or a remote response whose `size` or `hash` does not describe the bytes at hand; mutating the buffer between hashing and storing.

Common situations: TOCTOU between digest computation and store in producer code; copy-paste mixing digest/bytes pairs; sizes expressed in non-byte units when constructing CacheDigest manually.

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/928926baaa200370. Report an issue: GitHub.

Appendix: source

Thrown at crates/mise-cache-core/src/local.rs:60

    /// 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(())
        })
    }

    /// Atomically store a file after verifying its declared digest.
    pub fn store_file(&self, digest: &CacheDigest, source: &Path) -> Result<PathBuf> {
        self.store_file_inner(digest, source, true)
    }

    /// Store a file whose digest was already verified by this crate.
    pub(crate) fn store_verified_file(
        &self,
        digest: &CacheDigest,
        source: &Path,
    ) -> Result<PathBuf> {

View on GitHub (pinned to 6f52dcdf99)