jdx/mise · info

declined; nothing was changed

Error message

declined; nothing was changed

What it means

`mise history` (rollback/undo/apply) refreshes its plan before writing anything, and if the refreshed plan still contains unresolved conflicts it asks for confirmation. This error is thrown when the user (or a non-interactive caller answering 'no') declines that confirmation. It is a deliberate no-op guard: nothing on disk was touched.

Solutions

  1. Re-run with `--yes` if you intend to apply the plan non-interactively.
  2. Inspect the printed plan first; resolve conflicts (e.g. revert or manually restore the conflicting paths) so the refreshed plan is conflict-free.
  3. Run the command interactively and answer `y` when the plan looks correct.

Example fix

// before
mise history rollback
// error: declined; nothing was changed
// after
mise history rollback --yes
Defensive patterns

Strategy: validation

Validate before calling

if !has_conflicts(plan) { run_rollback_with_yes(); } else { review_plan_and_resolve(plan); }

Prevention

When it happens

Trigger: Running `mise history rollback`/`undo`/`apply` without `--yes` when the refreshed plan contains Action::Conflict steps; `prompt::confirm` returned a non-yes answer inside apply_steps.

Common situations: Non-interactive CI/script runs where confirm() cannot get a yes; a user reviewing the refreshed plan and choosing not to proceed because live files differ from the original plan.

Related errors


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

Appendix: source

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

    let mut live;
    loop {
        round += 1;
        // editors may have written while the prompt was open: re-plan
        live = live_tree(repo, tracked)?;
        let fresh = plan(repo, exec, &live)?;
        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;

View on GitHub (pinned to 533346cc37)