jdx/mise · error

checkpoint {} did not finish; there is no state to roll back

Error message

checkpoint {} did not finish; there is no state to roll back to

What it means

refuse_unusable() rejects checkpoints that cannot serve as a rollback source. A checkpoint still marked OperationStatus::Pending never finished recording, so there is no complete prior state to roll back to.

Source

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

            return Ok(Some(entry.clone()));
        }
        // held content that differs, or a known absence while the path now
        // exists, are both versions to return to
        let differs = saved.is_some()
            || matches!(
                classify(&entry.checkpoint, &tree_path_to_display(&tree_path)),
                PathState::Absent
            );
        if differs {
            return Ok(Some(entry.clone()));
        }
    }
    Ok(None)
}

fn refuse_unusable(entry: &Entry) -> Result<()> {
    if entry.checkpoint.status() == Some(OperationStatus::Pending) {
        bail!(
            "checkpoint {} did not finish; there is no state to roll back to",
            entry.id
        );
    }
    if entry.checkpoint.tree.snapshot.is_none() {
        bail!("checkpoint {} has no content snapshot", entry.id);
    }
    if entry.checkpoint.schema_version > super::store::SCHEMA_VERSION {
        bail!(
            "checkpoint {} was written by a newer mise (schema {})",
            entry.id,
            entry.checkpoint.schema_version
        );
    }
    Ok(())
}

/// Every path a checkpoint's coverage includes, as absolute paths.

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Pick a different, completed checkpoint to roll back to (verify status is not Pending)
  2. Re-run the original operation so it completes and produces a valid checkpoint
  3. Clean up the stale Pending entry from history if the tooling permits, then retry

Example fix

// before
mise history rollback <pending-id>   # errors
// after
mise history list   # choose a completed checkpoint
mise history rollback <completed-id>
Defensive patterns

Strategy: validation

Validate before calling

// only roll back to finished checkpoints
let target = entries.into_iter()
    .find(|e| e.checkpoint.status() != Some(OperationStatus::Pending))
    .expect("no completed checkpoint available");

Type guard

fn is_rollbackable(e: &Entry) -> bool {
    e.checkpoint.status() != Some(OperationStatus::Pending)
        && e.checkpoint.tree.snapshot.is_some()
}

Prevention

When it happens

Trigger: `mise history` rollback targets an entry whose checkpoint.status() == Some(Pending) — e.g. a previous operation crashed or was killed mid-checkpoint.

Common situations: A terminated mise process (SIGKILL, power loss, OOM) left a dangling Pending checkpoint; user picks the newest history entry which is the incomplete one.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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