jdx/mise · error
task cache artifact checksum mismatch
Error message
task cache artifact checksum mismatch
What it means
verify_artifact_checksum recomputes the artifact checksum from the manifest roots and the archive and compares it to manifest.artifact_checksum. A mismatch means the archived bytes no longer match what was recorded at save time — corruption, tampering, or a partially overwritten archive — so the cache refuses to restore untrusted content.
Source
Thrown at src/task/task_cache.rs:941
execution_duration_ns: manifest.execution_duration_ns,
archive_checksum,
};
let encoded = serde_json::to_string(&material)?;
Ok(format!("blake3:{}", hash::hash_blake3_to_str(&encoded)))
}
fn verify_artifact_checksum(manifest: &CacheManifest, archive_path: Option<&Path>) -> Result<()> {
let Some(expected) = &manifest.artifact_checksum else {
return Ok(());
};
let archive_path = if manifest.roots.is_empty() {
None
} else {
Some(archive_path.ok_or_else(|| eyre!("task cache archive is missing"))?)
};
let actual = calculate_artifact_checksum(manifest, archive_path)?;
if actual != *expected {
bail!("task cache artifact checksum mismatch");
}
Ok(())
}
pub(crate) fn task_cache_entries(task: &Task, root: &Path) -> Result<Vec<TaskCacheEntry>> {
Settings::get().ensure_experimental("task artifact caching")?;
let cache_dir = task_cache_dir();
if !cache_dir.is_dir() {
return Ok(Vec::new());
}
let identity = task_cache_identity(task, root);
let current_key = file::read_to_string(task_cache_state_path(task, root))
.ok()
.map(|key| key.trim().to_string());
let mut entries = Vec::new();
for entry in fs::read_dir(&cache_dir)? {
let entry = entry?;
let manifest_path = entry.path();View on GitHub (pinned to 6f52dcdf99)
Solutions
- Delete the affected entry (or wipe the cache dir) and re-run to regenerate the artifact
- If using a remote store, verify its integrity/headers and check for concurrent writers on the same key
- Ensure the cache volume is writable and stable (no disk-full, no flaky mounts)
- Treat unexpected checksum failures on a private cache as possible tampering and rotate the cache
Example fix
# shell
rm -rf "${XDG_CACHE_HOME:-$HOME/.cache}/task-artifacts/v2/<entry-dir>
mise run build Defensive patterns
Strategy: fallback
Validate before calling
# recompute and compare if you mirror caches externally cd /path/to/extract && find . -type f | sort | xargs sha256sum | sha256sum
Try / catch
Delete the entry, re-run uncached to regenerate, and if failures repeat on a private single-writer cache, investigate storage/bit-rot; on shared caches, treat as tampering and rotate.
Prevention
- Serve remote caches over verified TLS with integrity-checked uploads
- Prevent concurrent writers on one key
- Alert on repeated checksum failures — silent corruption elsewhere may follow
When it happens
Trigger: Restoring an entry whose archive was modified after save: bit rot, a concurrent writer replacing the artifact, a remote cache proxy serving truncated/mangled bodies, or manual edits inside the cache. The check runs during both restore paths via verify_artifact_checksum(manifest, archive_path).
Common situations: Shared remote cache with unreliable storage; NFS muting fsync semantics; two CI jobs racing on the same key; security-sensitive setups where this bail is the tamper alarm.
Related errors
- task {} cache outputs must not contain source {}
- unsupported task cache store version {}; expected {}
- task cache manifest contains duplicate or nested roots
- task cache archive is missing {}
- task cache manifest does not match cache key
AI-assisted analysis of jdx/mise@6f52dcdf99 (2026-08-22).
Data as JSON: /api/errors/7ea53eb97bb11689.
Report an issue: GitHub.