jdx/mise · error

cached OCI layer diff ID mismatch

Error message

cached OCI layer diff ID mismatch

What it means

After decompressing a cached OCI layer (read_cached_layer, src/oci/layer/cache.rs:143), mise hashes the uncompressed content and compares it to the recorded diff_id (the digest of the uncompressed tar). This error means the gunzipped layer content does not match the cached `diff_id` — the compressed blob may be valid gzip but not the layer originally recorded, or the cache record is stale/wrong.

Solutions

  1. Invalidate the OCI layer cache (delete the cache dir or the specific layer + record) and re-run so the layer is re-fetched with fresh metadata.
  2. Rebuild the tool layer from source instead of using the cache if the layer was produced locally.
  3. Update mise — earlier versions could write inconsistent digest/diff_id records; the current code validates both on read.
  4. Check that the source OCI layout/registry the cache came from is not serving mutated layers under the same digest.

Example fix

# before: diff ID mismatch during cached build
rm -rf ~/.cache/mise/oci
# after
mise build-push ...  # re-extracts layer and recomputes diff_id
Defensive patterns

Strategy: fallback

Validate before calling

// after decompressing, verify before use
let diff_id = format!("sha256:{}", hex_encode(Sha256::digest(&uncompressed)));
if diff_id != record.diff_id {
  eprintln!("cached diff_id stale; rebuilding layer");
  rebuild_layer(image_dir)?;
}

Try / catch

match read_cached_layer(...) {
  Err(e) if e.to_string().contains("diff ID mismatch") => {
    invalidate_cache_entry(record.digest);
    rebuild_or_refetch_layer(image_dir)
  }
  other => other,
}

Prevention

When it happens

Trigger: Calling read_cached_layer (via build_cached_tool_layer) where the gzipped blob passes digest validation but SHA-256 of its decompressed stream != record.diff_id. Causes: cache metadata written for a different layer version, corruption inside the gzip stream that still decompresses, or a registry/layout mismatch between digest and diff_id at cache-write time.

Common situations: Cache entries created by an older mise version with a differing layer build; tool image rebuilt upstream with the same tag so the cached diff_id no longer matches; corrupted multi-stream gzip; race between cache write and read.

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@533346cc37 (2026-09-17). Data as JSON: /api/errors/9528114518917970. Report an issue: GitHub.

Appendix: source

Thrown at src/oci/layer/cache.rs:143

    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,
        size: record.size,
        bytes,
    }))
}

fn write_cached_layer(record_path: &Path, cache_dir: &Path, blob: &LayerBlob) -> Result<()> {
    crate::file::create_dir_all(cache_dir)?;
    let blob_path = cache_dir.join(blob.digest.trim_start_matches("sha256:"));
    // Atomic blob publication followed by atomic metadata publication lets
    // concurrent builds share this cache without sharing an image index.
    crate::file::write_atomic(blob_path, &blob.bytes)?;
    crate::file::write_atomic(

View on GitHub (pinned to 533346cc37)