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 applying any step, apply_steps takes a protective checkpoint of the current state of every path the plan will write or delete. If that checkpoint could not be taken (scope.before() returned None), mise aborts with this error rather than mutating files it could not protect. Nothing was changed.

Solutions

  1. Check the history store directory is writable and not corrupted; run `mise history` listing to verify entries are being recorded.
  2. Retry the rollback/undo command; transient capture failures often clear on retry.
  3. Inspect `MISE_DEBUG=1` output for why the checkpoint capture returned nothing before forcing any manual restore.
Defensive patterns

Strategy: retry

Validate before calling

test -w "$(mise history dir 2>/dev/null || echo ~/.local/share/mise/history)" && echo writable

Try / catch

match result { Err(msg) if msg.contains("no protective checkpoint") => { fix_store(); retry(); }, other => other }

Prevention

When it happens

Trigger: scope.before() is None in apply_steps — the snapshot/checkpoint capture produced no entry id for the current scope, e.g. the history store or capture walk failed to record a usable 'before' state.

Common situations: Corrupt or unwritable history store; live tree capture failing for the target paths; unusual filesystem states that make snapshot capture return no checkpoint.

Related errors


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

Appendix: 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 533346cc37)