jdx/mise · error

checkpoint has no protective checkpoint to undo from

Error message

checkpoint {} has no protective checkpoint to undo from

What it means

Undo restores files from the 'before' protective checkpoint recorded on the operation. If the operation has no `before` checkpoint reference, undo cannot know what the files looked like beforehand and fails rather than guessing.

Solutions

  1. Manually restore the files from your own backup or git, then run `mise dot checkpoint`-style sync to re-baseline
  2. Drop the stale entry from history (or prune history) so undo targets valid operations instead
  3. Upgrade/re-run operations with a current mise version so future checkpoints capture `before` state
Defensive patterns

Strategy: fallback

Validate before calling

const op = entry?.operation;
if (op && !op.before) throw new Error('no protective before-checkpoint; restore manually');

Try / catch

try {
  await mise.dot.undo();
} catch (e) {
  if (/no protective checkpoint/.test(e.message)) {
    // fall back to manual restore from backup/git
  }
}

Prevention

When it happens

Trigger: Undoing a failed operation whose `op.before` is `None` — an operation that never captured a pre-operation snapshot (e.g. created before the protective-checkpoint mechanism, or snapshot capture failed).

Common situations: Old history entries created by a mise version without protective checkpoints; a corrupted or pruned history store losing the before-reference; undoing the very first entry in a freshly initialized history.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


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

Appendix: source

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

    let Some(op) = operation.checkpoint.operation.clone() else {
        bail!("checkpoint {} is not an operation", operation.id);
    };
    // Undo restores tracked files only, never package or service state.
    if op.status == OperationStatus::Pending {
        bail!(
            "checkpoint {} is still running or was interrupted; nothing to undo",
            operation.id
        );
    }
    if op.status == OperationStatus::Failed && !op.affected.is_empty() {
        info!(
            "history: operation {} failed midway; reversing the {} path(s) it changed",
            operation.id,
            op.affected.len()
        );
    }
    let Some(before_uuid) = &op.before else {
        bail!(
            "checkpoint {} has no protective checkpoint to undo from",
            operation.id
        );
    };
    let Some(before) = entries
        .iter()
        .find(|entry| &entry.checkpoint.uuid == before_uuid)
        .cloned()
    else {
        bail!(
            "checkpoint {} is unavailable; cannot find the state before operation {}",
            before_uuid,
            operation.id
        );
    };
    if op.affected.is_empty() {
        info!("history: operation {} touched nothing", operation.id);
        return Ok(());

View on GitHub (pinned to 533346cc37)