{"record":{"id":"b2de4288ae878313","repo":"jdx/mise","slug":"cannot-protect-reason","errorCode":null,"errorMessage":"cannot protect {}: {reason}","messagePattern":"cannot protect (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/checkpoint/preimages.rs","lineNumber":244,"sourceCode":"                    for link in links {\n                        self.snapshot(\n                            &path.join(&link.rel),\n                            &PathSnapshot::Symlink {\n                                dest: link.dest.clone(),\n                            },\n                            tree,\n                        )?;\n                    }\n                }\n            }\n            PathSnapshot::Directory { mode } => {\n                if self.eligible(path)? {\n                    self.mode(path, Some(*mode));\n                }\n            }\n            PathSnapshot::Unrecorded { reason, .. } => {\n                if self.eligible(path)? {\n                    eyre::bail!(\"cannot protect {}: {reason}\", display_path(path));\n                }\n            }\n        }\n        Ok(())\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::system::files::{FileMode, FilePolicy};\n    use crate::system::history::journal::Capture;\n\n    #[test]\n    fn first_preimages_survive_multiple_phases_without_saving_siblings() -> Result<()> {\n        let state = tempfile::tempdir()?;\n        let live =\n            tempfile::tempdir_in(crate::system::history::sync::layout::Roots::current().home)?;","sourceCodeStart":226,"sourceCodeEnd":262,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/history/checkpoint/preimages.rs#L226-L262","documentation":"During a preimage snapshot, snapshot walks paths and records their modes when they are eligible for protection. If a path resolves to PathSnapshot::Unrecorded with a reason (e.g. the path's state could not be captured), and the path is otherwise eligible, protecting history would be incomplete, so it aborts with 'cannot protect <path>: <reason>'. The bundled reason explains exactly why the snapshot could not record it.","triggerScenarios":"Calling the history snapshot/preimage capture for a path that is eligible for protection but whose PathSnapshot came back Unrecorded { reason }, e.g. unreadable files, files that changed mid-snapshot, or unsupported file types.","commonSituations":"History protection enabled while the working tree contains files the snapshotter cannot record: permission-restricted files, sockets/fifos, rapidly changing files, or paths deleted between listing and snapshot.","solutions":["Read the <reason> in the message and fix the underlying cause (permissions, file type, or file churn) for the named path","Exclude the problematic path from history protection via the history ignore/exclusion configuration","Re-run the operation after the path is stable; transient races (file replaced during snapshot) usually resolve on retry"],"exampleFix":"// before: snapshot fails on an unreadable path\n// cannot protect /etc/secret.key: permission denied\n\n// after: exclude the path from protection\n// [history]\n// ignore = [\"/etc/secret.key\"]","handlingStrategy":"try-catch","validationCode":"# ensure paths are snapshot-able before enabling protection\nfor f in $WATCHED_PATHS; do\n  [ -r \"$f\" ] || echo \"warning: $f not readable; exclude it from history protection\" >&2\ndone","typeGuard":null,"tryCatchPattern":"match history::snapshot() {\n    Err(e) if e.to_string().starts_with(\"cannot protect\") => {\n        // parse the path and reason, exclude the path, retry once\n    }\n    r => r?,\n}","preventionTips":["Exclude special files (sockets, fifos) and unreadable secrets from protection","Avoid mutating watched paths while a snapshot runs","Read the reason in the message; it names the exact filesystem problem"],"tags":["history","snapshot","filesystem"],"backgroundTag":"file-read-failed","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}