{"record":{"id":"83bcd19cb4286f08","repo":"jdx/mise","slug":"recovery-content-failed-verification","errorCode":null,"errorMessage":"recovery content failed verification","messagePattern":"recovery content failed verification","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/recovery.rs","lineNumber":143,"sourceCode":"    Ok(())\n}\n\npub(super) fn read_blob(state_dir: &Path, blob: &Blob) -> Result<Vec<u8>> {\n    use base64::Engine;\n    validate_blob_id(&blob.sha256)?;\n    let bytes = match &blob.inline {\n        Some(inline) => base64::engine::general_purpose::STANDARD.decode(inline)?,\n        None => {\n            let path = super::journal::blobs_dir_in(state_dir).join(&blob.sha256);\n            let metadata = std::fs::symlink_metadata(&path)?;\n            if !metadata.is_file() || metadata.len() != blob.size {\n                bail!(\"invalid recovery content file\");\n            }\n            std::fs::read(path)?\n        }\n    };\n    if bytes.len() as u64 != blob.size || hex::encode(sha2::Sha256::digest(&bytes)) != blob.sha256 {\n        bail!(\"recovery content failed verification\");\n    }\n    Ok(bytes)\n}\n\nfn validate_snapshot(state_dir: &Path, snapshot: &PathSnapshot) -> Result<()> {\n    match snapshot {\n        PathSnapshot::File { content, .. } => {\n            read_blob(state_dir, content)?;\n        }\n        PathSnapshot::Dir {\n            files, links, dirs, ..\n        } => {\n            let mut seen = BTreeSet::new();\n            for relative in files\n                .iter()\n                .map(|f| &f.rel)\n                .chain(links.iter().map(|f| &f.rel))\n                .chain(dirs.iter().map(|f| &f.rel))","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/history/recovery.rs#L125-L161","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (corrupt blob)\n$ sha256sum blobs/ca9781...\ndeadbeef...  (expected ca978112...)\n\n// after (restored matching blob)\n$ sha256sum blobs/ca9781...\nca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb\n$ mise bootstrap dotfiles recover","handlingStrategy":"fallback","validationCode":"// verify a blob's integrity yourself before recovery\nlet bytes = std::fs::read(blobs_dir.join(&blob.sha256))?;\nuse sha2::{Digest, Sha256};\nassert_eq!(hex::encode(Sha256::digest(&bytes)), blob.sha256, \"blob corrupt\");","typeGuard":null,"tryCatchPattern":"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? }","preventionTips":["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"],"tags":["checksum","sha256","integrity","recovery"],"backgroundTag":"checksum-mismatch","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}