jdx/mise · error
recovery content failed verification
Error message
recovery content failed verification
What it means
After loading blob bytes (inline or from disk), read_blob verifies both the length and the SHA-256 digest against the recorded Blob metadata. This bail means the content does not match its recorded hash — the stored preimage is corrupted, tampered with, or was written with a mismatched record. Recovery refuses to restore unverified data.
Source
Thrown at src/system/history/recovery.rs:143
Ok(())
}
pub(super) fn read_blob(state_dir: &Path, blob: &Blob) -> Result<Vec<u8>> {
use base64::Engine;
validate_blob_id(&blob.sha256)?;
let bytes = match &blob.inline {
Some(inline) => base64::engine::general_purpose::STANDARD.decode(inline)?,
None => {
let path = super::journal::blobs_dir_in(state_dir).join(&blob.sha256);
let metadata = std::fs::symlink_metadata(&path)?;
if !metadata.is_file() || metadata.len() != blob.size {
bail!("invalid recovery content file");
}
std::fs::read(path)?
}
};
if bytes.len() as u64 != blob.size || hex::encode(sha2::Sha256::digest(&bytes)) != blob.sha256 {
bail!("recovery content failed verification");
}
Ok(bytes)
}
fn validate_snapshot(state_dir: &Path, snapshot: &PathSnapshot) -> Result<()> {
match snapshot {
PathSnapshot::File { content, .. } => {
read_blob(state_dir, content)?;
}
PathSnapshot::Dir {
files, links, dirs, ..
} => {
let mut seen = BTreeSet::new();
for relative in files
.iter()
.map(|f| &f.rel)
.chain(links.iter().map(|f| &f.rel))
.chain(dirs.iter().map(|f| &f.rel))View on GitHub (pinned to afd2eddd3a)
Solutions
- Do not trust the corrupted preimage; accept the file's current contents with `recover <operation> --keep-current`.
- Restore the correct blob from a backup of the state directory so its SHA-256 matches the journal, then rerun recovery.
- Reconstruct the intended preimage manually from your dotfiles repo; check storage health (fsck/S.M.A.R.T.) if corruption recurs.
Example fix
// before (corrupt blob) $ sha256sum blobs/ca9781... deadbeef... (expected ca978112...) // after (restored matching blob) $ sha256sum blobs/ca9781... ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb $ mise bootstrap dotfiles recover
Defensive patterns
Strategy: fallback
Validate before calling
// verify a blob's integrity yourself before recovery
let bytes = std::fs::read(blobs_dir.join(&blob.sha256))?;
use sha2::{Digest, Sha256};
assert_eq!(hex::encode(Sha256::digest(&bytes)), blob.sha256, "blob corrupt"); Try / catch
match result { Err(e) if e.to_string().contains("recovery content failed verification") => /* use --keep-current; restore the blob from a verified backup */, other => other? } Prevention
- Back up the state directory so corrupt blobs can be replaced with matching copies
- Investigate disk health (S.M.A.R.T., fsck) if checksum failures recur
- Exclude the mise state directory from file-sync tools that may rewrite blobs
When it happens
Trigger: read_blob, called from validate_snapshot (recover_path) or restore, decodes/reads bytes whose hex(SHA-256) != blob.sha256 or whose length != blob.size — e.g. bit rot, an inline base64 payload that decodes to the wrong content, or a blob file rewritten with different data.
Common situations: Disk corruption or a failing SSD, a file-sync client altered state-dir blobs, someone edited a config file's stored preimage, or an interrupted write left the blob inconsistent with the journal.
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
- brew-cask:{}: cask metadata has no sha256
- {name}: sha256 is {actual}, the packslip says {}
- remote cache blob pack failed digest verification
- verified checksum file digest does not match existing checks
- packslip:{project}@{version}: manifest digest differs from s
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/83bcd19cb4286f08.
Report an issue: GitHub.