{"record":{"id":"8cc8567ac247f1f2","repo":"jdx/mise","slug":"changed-after-it-was-protected-nothing-more-wa","errorCode":null,"errorMessage":"{} changed after it was protected; nothing more was changed","messagePattern":"(.+?) changed after it was protected; nothing more was changed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/replay.rs","lineNumber":614,"sourceCode":"            if removed {\n                let affected = display_path(&step.path);\n                scope.with_operation(|op| {\n                    op.affected.push(affected.clone());\n                    if let Some(bits) = bits {\n                        op.directory_modes.insert(affected.clone(), bits);\n                    }\n                    op.directories.push(affected);\n                });\n                touched.push(step.path.clone());\n            }\n            continue;\n        }\n        // a file created or changed since the verified sample was never\n        // protected: stop here; what was already written is recorded below\n        // and undo can reverse it\n        let expected = repo.restored_object_at(&live, &step.tree_path)?;\n        if !same_object(&expected, &current_object(repo, &step.path)?) {\n            bail!(\n                \"{} changed after it was protected; nothing more was changed\",\n                display_path(&step.path)\n            );\n        }\n        let was_directory = step.path.is_dir() && !step.path.is_symlink();\n        let mut empty_dirs = vec![];\n        if was_directory && !matches!(&step.action, Action::Write { mode, .. } if mode == \"040000\")\n        {\n            // replacing or removing a directory removes everything inside\n            // it: a file history would capture must be a step of this plan\n            // (else it appeared after protection); a file history never\n            // covers goes with it, said out loud; empty subdirectories\n            // leave no trace in a snapshot and are recorded for undo\n            let inside = directory_contents(&step.path, steps, tracked)?;\n            if let Some(stray) = inside.appeared.first() {\n                bail!(\n                    \"{} appeared after {} was protected; nothing more was changed\",\n                    display_path(stray),","sourceCodeStart":596,"sourceCodeEnd":632,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/history/replay.rs#L596-L632","documentation":"When applying a restore step, mise compares the file's current content hash against the object recorded in the protective checkpoint. If the live file differs from what was protected, the file was modified after the checkpoint — applying the restore on top would silently destroy unsaved changes — so mise stops at that point. Steps already written are recorded and can be undone.","triggerScenarios":"A target file's current_object differs from repo.restored_object_at(tree_path) during apply_steps, i.e. the file changed between checkpoint capture/verification and step application.","commonSituations":"An editor autosave, watcher, or build tooling rewrote a source file mid-restore; the user edited files while a long rollback was in progress.","solutions":["Re-run the rollback with no other processes writing to the target tree (stop editors/watchers).","If the current content is disposable, take a fresh checkpoint/undo cycle so the new state is protected, then retry.","Compare the live file to what you expect; if the new content is intentional, cancel the restore instead of forcing it."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"git status --porcelain <target-paths>  # ensure clean before rolling back","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Don't edit target files while a restore is running.","Close editors with autosave on the affected tree before rollback.","Re-run promptly: the shorter the window between checkpoint and apply, the lower the risk."],"tags":["history","checkpoint","concurrency","safety"],"backgroundTag":"concurrent-modification-detected","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"}