jdx/mise · error
changed after it was protected; nothing more was changed
Error message
{} changed after it was protected; nothing more was changed What it means
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.
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.
Defensive patterns
Strategy: validation
Validate before calling
git status --porcelain <target-paths> # ensure clean before rolling back
Prevention
- 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.
When it happens
Trigger: 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.
Common situations: An editor autosave, watcher, or build tooling rewrote a source file mid-restore; the user edited files while a long rollback was in progress.
Related errors
- appeared after was protected; nothing more was changed
- no protective checkpoint could be taken; nothing was changed
- these paths keep changing while being protected; nothing…
- another history operation is running
- another history operation is running
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/8cc8567ac247f1f2.
Report an issue: GitHub.
Appendix: source
Thrown at src/system/history/replay.rs:614
if removed {
let affected = display_path(&step.path);
scope.with_operation(|op| {
op.affected.push(affected.clone());
if let Some(bits) = bits {
op.directory_modes.insert(affected.clone(), bits);
}
op.directories.push(affected);
});
touched.push(step.path.clone());
}
continue;
}
// a file created or changed since the verified sample was never
// protected: stop here; what was already written is recorded below
// and undo can reverse it
let expected = repo.restored_object_at(&live, &step.tree_path)?;
if !same_object(&expected, ¤t_object(repo, &step.path)?) {
bail!(
"{} changed after it was protected; nothing more was changed",
display_path(&step.path)
);
}
let was_directory = step.path.is_dir() && !step.path.is_symlink();
let mut empty_dirs = vec![];
if was_directory && !matches!(&step.action, Action::Write { mode, .. } if mode == "040000")
{
// replacing or removing a directory removes everything inside
// it: a file history would capture must be a step of this plan
// (else it appeared after protection); a file history never
// covers goes with it, said out loud; empty subdirectories
// leave no trace in a snapshot and are recorded for undo
let inside = directory_contents(&step.path, steps, tracked)?;
if let Some(stray) = inside.appeared.first() {
bail!(
"{} appeared after {} was protected; nothing more was changed",
display_path(stray),View on GitHub (pinned to 533346cc37)