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, &current_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

  1. Stop processes that modify the working tree and re-run the replay
  2. Re-take the plan/checkpoint so protection reflects current content, then apply
  3. 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

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


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/8cc8567ac247f1f2. Report an issue: GitHub.