jdx/mise · error · eyre::Report

cached {description} failed digest verification

Error message

cached {description} failed digest verification

What it means

read_verified_blob() re-hashes a cached blob with blake3 and compares against the digest recorded in the action manifest (src/cache/rustc.rs:525-531). A mismatch means the file content changed after it was stored: silent corruption (bit rot, truncated write), external modification, or a tampered cache. The entry is rejected and the shim falls back to a real compile, so correctness is preserved — only the cache hit is lost.

Source

Thrown at src/cache/rustc.rs:529

fn read_canonical_blob<T>(path: &Path, digest: &CacheDigest, description: &str) -> Result<T>
where
    T: DeserializeOwned + Serialize,
{
    let bytes = read_verified_blob(path, digest, description)?;
    let value = serde_json::from_slice(&bytes)
        .wrap_err_with(|| format!("cached {description} is not valid JSON"))?;
    if canonical_json(&value)? != bytes {
        bail!("cached {description} is not canonical JSON");
    }
    Ok(value)
}

fn read_verified_blob(path: &Path, digest: &CacheDigest, description: &str) -> Result<Vec<u8>> {
    let mut bytes = Vec::new();
    std::fs::File::open(path)?.read_to_end(&mut bytes)?;
    if !digest.matches_bytes(&bytes)? {
        bail!("cached {description} failed digest verification");
    }
    Ok(bytes)
}

fn validated_outputs(
    directory: CacheDirectory,
    outputs: &RustcOutputs,
) -> Result<Vec<(CacheFileNode, PathBuf)>> {
    if directory.version != 1 || !directory.directories.is_empty() || !directory.symlinks.is_empty()
    {
        bail!("cached rustc output directory has unsupported entries");
    }
    let mut expected = outputs
        .files
        .iter()
        .chain(std::iter::once(&outputs.dep_info))
        .map(|path| {
            let name = path

View on GitHub (pinned to 6f52dcdf99)

Solutions

  1. Delete the affected cache directory — corrupted blobs cannot be repaired, only regenerated by recompiling or re-fetched from a healthy remote
  2. Exclude the mise cache directory from sync, backup, and antivirus scanning
  3. If failures recur, check filesystem/disk health (dmesg, smartctl) — repeated digest failures are an early corruption signal
  4. With a remote cache configured, a later clean run re-uploads valid blobs
Defensive patterns

Strategy: fallback

Validate before calling

fn blob_ok(path: &Path, digest: &CacheDigest) -> bool {
    std::fs::read(path)
        .map(|bytes| digest.matches_bytes(&bytes).unwrap_or(false))
        .unwrap_or(false)
}

Try / catch

Mirror the shim: on any integrity failure, drop the cached entry and recompile — `if !blob_ok(&path, &digest) { /* delete entry, run rustc */ }`. Never attempt partial restores from a blob that failed verification.

Prevention

When it happens

Trigger: restore_result reading the action descriptor (src/cache/rustc.rs:306), the metadata/output-root blobs, the stdout/stderr blobs (src/cache/rustc.rs:334-335), or a staged output file whose content no longer hashes to its recorded digest: bit flips on disk, partial writes from a crashed session, or files rewritten by backup/sync/antivirus software.

Common situations: Cloud-sync or backup tools rewriting files inside the cache dir; a failing disk; a cache copied between machines with a lossy transfer; another process writing into the CAS.

Related errors


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