jdx/mise · error

checkpoint is not an operation

Error message

checkpoint {} is not an operation

What it means

`mise dot undo` operates on checkpoints that record a file operation (create/update/delete of tracked files). Some history entries are checkpoints without an operation payload (e.g. protective snapshots), and undo refuses to act on them since there is nothing meaningful to reverse.

Solutions

  1. Run `mise dot history` and undo only entries that record an operation
  2. If undoing repeatedly, stop when you reach the last real operation; further undo has no effect
  3. If a specific checkpoint id was requested, verify it is an operation checkpoint, not a protective snapshot
Defensive patterns

Strategy: validation

Validate before calling

const entry = await mise.dot.history().then(h => h.find(e => e.id === id));
if (!entry?.operation) throw new Error(`${id} is not an operation checkpoint`);

Try / catch

try {
  await mise.dot.undo();
} catch (e) {
  if (/is not an operation/.test(e.message)) {
    // pick a different checkpoint from history
  }
}

Prevention

When it happens

Trigger: Selecting a history entry whose `checkpoint.operation` is `None` during undo — e.g. undoing past the point where real operations end and hitting a bare/protective checkpoint.

Common situations: Repeated `mise dot undo` calls walking past the first non-operation checkpoint in history; pointing undo at a checkpoint id that is a snapshot rather than an operation record.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

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

        undoes_of.insert(entry.checkpoint.uuid.clone(), target);
    }
    let operation = match &req.reference {
        Some(reference) => crate::cli::dotfiles::history::resolve(reference, &entries, None)?,
        None => entries
            .iter()
            .rev()
            .find(|entry| {
                entry.checkpoint.operation.as_ref().is_some_and(|op| {
                    op.status != OperationStatus::Pending
                        && op.before.is_some()
                        && !op.affected.is_empty()
                }) && !undone.contains(&entry.checkpoint.uuid)
            })
            .cloned()
            .ok_or_else(|| eyre::eyre!("nothing to undo: no tracked-file operation is left"))?,
    };
    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",

View on GitHub (pinned to 533346cc37)