jdx/mise · error

checkpoint {} has no protective checkpoint to undo from

Error message

checkpoint {} has no protective checkpoint to undo from

What it means

Every undoable operation records a protective `before` checkpoint UUID capturing the state prior to the operation. Undo restores from that checkpoint; if op.before is None the protective snapshot was never recorded, so there is no state to restore to and mise bails.

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 afd2eddd3a)

Solutions

  1. Use rollback with explicit paths or `--to <ref> --all` to restore files from a known checkpoint instead
  2. Check `mise bootstrap dotfiles history` for checkpoints that do have before-state
  3. If the store is corrupted, re-initialize dotfiles tracking and re-snapshot

Example fix

// before
mise bootstrap dotfiles undo   # operation lacks before-checkpoint
// after
mise bootstrap dotfiles rollback --to <known-ref> --all
Defensive patterns

Strategy: validation

Validate before calling

const entry = await getCheckpoint(id);
if (entry?.checkpoint?.operation && !entry.checkpoint.operation.before) {
  throw new Error(`checkpoint ${id} has no protective before-checkpoint`);
}

Type guard

const hasBefore = (op: Operation): op is Operation & { before: string } =>
  typeof op.before === "string" && op.before.length > 0;

Try / catch

try {
  await undo();
} catch (e) {
  if (String(e).includes("no protective checkpoint")) {
    await rollback({ paths: knownPaths });
  } else throw e;
}

Prevention

When it happens

Trigger: Running undo against an operation whose op.before is None — the operation was created without a pre-operation snapshot (older format, snapshot skipped, or corrupted record).

Common situations: History entries created by an older mise version before protective checkpoints were recorded; manually edited/corrupted history store; operations that bypassed checkpoint creation.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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