jdx/mise · error
cached OCI layer digest mismatch
Error message
cached OCI layer digest mismatch
What it means
While validating a cached OCI layer in read_cached_layer (src/oci/layer/cache.rs:131), mise recomputes the SHA-256 of the gzipped layer blob on disk and compares it to the digest recorded in the cache metadata. This error means the content hash does not match `record.digest`: the blob file was modified, corrupted, or swapped after being cached, even though its size happened to match.
Solutions
- Delete the affected cached layer (file named <digest> in the OCI cache dir) — or the whole OCI cache — and let mise re-download/rebuild it.
- Re-run the layer-producing operation online so the cache is repopulated from the trusted source.
- Investigate disk/filesystem health if multiple entries fail validation (memory or disk corruption).
- Avoid manual writes into the OCI cache and don't share one cache dir concurrently across independent builds.
Example fix
# before: digest mismatch on layer sha256:abc... rm ~/.cache/mise/oci/layers/sha256:abc... # after: layer re-fetched and validated mise build-push ...
Defensive patterns
Strategy: fallback
Validate before calling
let bytes = std::fs::read(blob_path)?;
let actual = Sha256::digest(&bytes);
if format!("sha256:{x}", x = hex::encode(actual)) != record.digest {
eprintln!("cache digest mismatch; invalidating");
std::fs::remove_file(blob_path)?;
} Try / catch
match read_cached_layer(...) {
Err(e) if e.to_string().contains("digest mismatch") => {
invalidate_cache_entry(digest);
fetch_layer_fresh(digest)
}
other => other,
} Prevention
- Treat the OCI cache as opaque — never write or swap files in it
- Avoid concurrent builds sharing one cache directory
- Investigate disk health if validation failures recur
When it happens
Trigger: Calling read_cached_layer (via build_cached_tool_layer) where bytes.len() == record.size but sha256(bytes) != record.digest. Causes include bit-rot/corruption, in-place tampering or manual edits, a hash-collision-shaped bug (overwritten blob of identical size from another layer), or unsafe shared-cache writes.
Common situations: Cache directories shared across machines or manipulated by other tools; disk corruption where file size survives but content changed; manually 'fixing' a cache entry by copying a different layer file in; concurrent builds racing on the same cache path.
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
- cached OCI layer diff ID mismatch
- cached OCI layer size mismatch
- base image has layers in its manifest but diff_ids in its…
- base image has layers in its manifest but diff_ids in its…
- blob digest mismatch: got
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/23c6ec42dc306f6b.
Report an issue: GitHub.
Appendix: source
Thrown at src/oci/layer/cache.rs:131
hash.update(bytes);
}
fn read_cached_layer(record_path: &Path, cache_dir: &Path) -> Result<Option<LayerBlob>> {
let record = match std::fs::read(record_path) {
Ok(bytes) => bytes,
Err(err) if err.kind() == std::io::ErrorKind::NotFound => return Ok(None),
Err(err) => return Err(err.into()),
};
let record: CachedLayer = serde_json::from_slice(&record)?;
crate::oci::layout::validate_sha256_digest(&record.digest)?;
crate::oci::layout::validate_sha256_digest(&record.diff_id)?;
let bytes = std::fs::read(cache_dir.join(record.digest.trim_start_matches("sha256:")))?;
eyre::ensure!(
bytes.len() as u64 == record.size,
"cached OCI layer size mismatch"
);
let digest = format!("sha256:{}", hex_encode(&Sha256::digest(&bytes)));
eyre::ensure!(digest == record.digest, "cached OCI layer digest mismatch");
let mut decoder = flate2::read::GzDecoder::new(bytes.as_slice());
let mut hash = Sha256::new();
let mut buffer = [0; 64 * 1024];
loop {
let n = decoder.read(&mut buffer)?;
if n == 0 {
break;
}
hash.update(&buffer[..n]);
}
let diff_id = format!("sha256:{}", hex_encode(&hash.finalize()));
eyre::ensure!(
diff_id == record.diff_id,
"cached OCI layer diff ID mismatch"
);
Ok(Some(LayerBlob {
digest,
diff_id,View on GitHub (pinned to 533346cc37)