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 restoring a step, replay compares the file's current object against the object captured at protection time. If they differ, the file changed after the protective checkpoint was taken, so replay stops before doing more damage; already-applied steps are recorded for undo.
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 afd2eddd3a)
Solutions
- Stop processes that modify the working tree and re-run the replay
- Re-take the plan/checkpoint so protection reflects current content, then apply
- Use undo (`mise history undo`) to reverse the partially applied steps, then retry cleanly
Defensive patterns
Strategy: retry
Validate before calling
// verify file is stable immediately before applying
let h1 = hash_file(path)?;
std::thread::sleep(Duration::from_millis(200));
let h2 = hash_file(path)?;
assert_eq!(h1, h2, "{} is being modified concurrently", path); Try / catch
match result {
Err(e) if e.to_string().contains("changed after it was protected") => {
// already-applied steps are undoable
run_undo();
}
other => other?,
} Prevention
- Disable editor autosave/formatters while a replay runs
- Don't edit files during long replays; run undo afterward if partial work occurred
- Apply plans on a quiet tree
When it happens
Trigger: A planned step's target path was modified (or created) between the protective checkpoint verification and the moment that step is applied — repo.restored_object_at(&live,...) != current_object(repo, path).
Common situations: Editor autosave, formatter-on-save, or a build process touches the file mid-replay; user edits files while a long replay is running.
Related errors
- these paths keep changing while being protected; nothing was
- {} appeared after {} was protected; nothing more was changed
- the refreshed plan has conflicts; nothing was changed
- declined; nothing was changed
- {} cannot be recreated as a directory: something else is the
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/8cc8567ac247f1f2.
Report an issue: GitHub.