{"record":{"id":"0358a2c4098adbd4","repo":"jdx/mise","slug":"cannot-safely-change-without-a-recovery-preimag","errorCode":null,"errorMessage":"cannot safely change {} without a recovery preimage: {reason}","messagePattern":"cannot safely change (.+?) without a recovery preimage: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/journal.rs","lineNumber":534,"sourceCode":"}\n\n/// [`begin_changes`] with a capture depth per path. Fails when an entry\n/// cannot be persisted: the mutation must not go ahead without its\n/// write-ahead record.\npub(crate) fn begin_changes_with(\n    part: &str,\n    item: &str,\n    paths: impl IntoIterator<Item = (PathBuf, Capture)>,\n) -> Result<Vec<PendingChange>> {\n    if !super::scope::is_active() {\n        return Ok(vec![]);\n    }\n    let mut pending = vec![];\n    for (path, capture) in paths {\n        let prior = PathSnapshot::capture_with(&dirs::STATE, &path, capture);\n        if let PathSnapshot::Unrecorded { reason, .. } = &prior {\n            if super::scope::requires_recovery_preimage() {\n                eyre::bail!(\n                    \"cannot safely change {} without a recovery preimage: {reason}\",\n                    display_path(&path)\n                );\n            }\n            warn!(\n                \"bootstrap: temporary recovery is unavailable for {}: {reason}; proceeding with deployment\",\n                display_path(&path)\n            );\n        }\n        if let Some(seq) = super::scope::record(JournalEntry::PathChanged {\n            part: part.to_string(),\n            item: item.to_string(),\n            path: path.clone(),\n            prior,\n        })? {\n            pending.push(PendingChange { seq, path });\n        }\n    }","sourceCodeStart":516,"sourceCodeEnd":552,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/history/journal.rs#L516-L552","documentation":"Thrown by `journal::begin_changes_with` (via `begin_changes`) when a path scheduled for modification could not be captured as a recovery preimage (`PathSnapshot::Unrecorded`) and the current scope `requires_recovery_preimage()`. The journal needs a 'before' copy to enable rollback; without it, changing the file would be unrecoverable, so the library refuses to proceed.","triggerScenarios":"Beginning a journaled change to a file that cannot be snapshotted — unreadable file, symlink/special-file the capture backend doesn't support, or a path outside the managed tree — while inside a strict scope that demands recovery preimages.","commonSituations":"Corrupted permissions on a managed dotfile after a restore; files replaced by symlinks by another tool; state directory partially deleted; running with a strict recovery scope after a previous interrupted journal.","solutions":["Fix the underlying capture problem reported in `{reason}` — usually restore read permissions or replace a broken symlink with a real file.","Re-initialize the affected path from the repository so a valid preimage can be captured.","Run outside the strict recovery scope (bootstrap mode) where the library only warns instead of failing.","Inspect the state directory for missing/corrupt snapshot data and repair or clear it."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// before the operation: test -r \"$FILE\" && [ ! -L \"$FILE\" ] || echo \"cannot snapshot $FILE\"","typeGuard":null,"tryCatchPattern":"// catch \"cannot safely change ... without a recovery preimage\"\n// -> repair the path (permissions/symlink) then retry, or re-run in bootstrap scope","preventionTips":["Keep managed files real, readable files — not broken symlinks or special files.","Don't manually chmod managed dotfiles to unreadable modes.","Let the tool complete journal recovery after interruptions instead of deleting state."],"tags":["journal","recovery","snapshot","file"],"backgroundTag":"file-read-failed","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}