jdx/mise · error

no protective checkpoint could be taken; nothing was changed

Error message

no protective checkpoint could be taken; nothing was changed

What it means

Before writing anything, replay takes a protective checkpoint (scope.before()) so the operation can be undone. If no checkpoint id can be produced, mise aborts rather than apply changes with no safety net.

Source

Thrown at src/system/history/replay.rs:511

        let changed = actionable(&fresh) != actionable(steps);
        if changed {
            *steps = fresh.clone();
            miseprintln!("history: the working tree changed since the plan was shown:");
            print_plan(steps, exec, tracked)?;
            if steps
                .iter()
                .any(|step| matches!(step.action, Action::Conflict(_)))
            {
                bail!("the refreshed plan has conflicts; nothing was changed");
            }
            if !exec.yes && !prompt::confirm("history: apply the refreshed plan?")?.is_yes() {
                bail!("declined; nothing was changed");
            }
        }
        // completeness: every path about to be written or deleted that exists
        // now must be captured, as it is now, in the protective checkpoint
        let Some((before_id, _)) = scope.before() else {
            bail!("no protective checkpoint could be taken; nothing was changed");
        };
        let before = store::entry(store, before_id)?;
        let before_tree = before
            .checkpoint
            .tree
            .snapshot
            .clone()
            .ok_or_else(|| eyre::eyre!("the protective checkpoint has no content"))?;
        let mut missing = vec![];
        for step in steps.iter().filter(|step| step.action.mutates()) {
            let Some(current) = repo.restored_object_at(&live, &step.tree_path)? else {
                continue;
            };
            if repo.restored_object_at(&before_tree, &step.tree_path)? != Some(current) {
                missing.push(step.path.clone());
            }
        }
        if missing.is_empty() {

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Check that the history/checkpoint store is writable and healthy (disk space, permissions)
  2. Run `mise doctor` / inspect history store state for corruption
  3. Retry the command; if persistent, report with MISE_DEBUG=1 output
Defensive patterns

Strategy: try-catch

Validate before calling

// preflight: ensure the history store is writable
let store_dir = mise_history_dir();
assert!(store_dir.metadata()?.permissions().readonly() == false, "history store must be writable");

Try / catch

match result {
    Err(e) if e.to_string().contains("no protective checkpoint") => {
        eprintln!("check history store health (disk space, permissions)");
    }
    other => other?,
}

Prevention

When it happens

Trigger: scope.before() returns None during apply_steps — the protective snapshot of the current state could not be created (e.g. snapshotting machinery failed to yield an entry id).

Common situations: Snapshot store unavailable or refuses to record the pre-apply state; running in an environment where the protective capture cannot be persisted.

Related errors


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