{"record":{"id":"01589bdeafd8ecf5","repo":"jdx/mise","slug":"checkpoint-is-not-an-operation","errorCode":null,"errorMessage":"checkpoint {} is not an operation","messagePattern":"checkpoint (.+?) is not an operation","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/replay.rs","lineNumber":272,"sourceCode":"        undoes_of.insert(entry.checkpoint.uuid.clone(), target);\n    }\n    let operation = match &req.reference {\n        Some(reference) => crate::cli::dotfiles::history::resolve(reference, &entries, None)?,\n        None => entries\n            .iter()\n            .rev()\n            .find(|entry| {\n                entry.checkpoint.operation.as_ref().is_some_and(|op| {\n                    op.status != OperationStatus::Pending\n                        && op.before.is_some()\n                        && !op.affected.is_empty()\n                }) && !undone.contains(&entry.checkpoint.uuid)\n            })\n            .cloned()\n            .ok_or_else(|| eyre::eyre!(\"nothing to undo: no tracked-file operation is left\"))?,\n    };\n    let Some(op) = operation.checkpoint.operation.clone() else {\n        bail!(\"checkpoint {} is not an operation\", operation.id);\n    };\n    // Undo restores tracked files only, never package or service state.\n    if op.status == OperationStatus::Pending {\n        bail!(\n            \"checkpoint {} is still running or was interrupted; nothing to undo\",\n            operation.id\n        );\n    }\n    if op.status == OperationStatus::Failed && !op.affected.is_empty() {\n        info!(\n            \"history: operation {} failed midway; reversing the {} path(s) it changed\",\n            operation.id,\n            op.affected.len()\n        );\n    }\n    let Some(before_uuid) = &op.before else {\n        bail!(\n            \"checkpoint {} has no protective checkpoint to undo from\",","sourceCodeStart":254,"sourceCodeEnd":290,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/history/replay.rs#L254-L290","documentation":"`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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Run `mise dot history` and undo only entries that record an operation","If undoing repeatedly, stop when you reach the last real operation; further undo has no effect","If a specific checkpoint id was requested, verify it is an operation checkpoint, not a protective snapshot"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const entry = await mise.dot.history().then(h => h.find(e => e.id === id));\nif (!entry?.operation) throw new Error(`${id} is not an operation checkpoint`);","typeGuard":null,"tryCatchPattern":"try {\n  await mise.dot.undo();\n} catch (e) {\n  if (/is not an operation/.test(e.message)) {\n    // pick a different checkpoint from history\n  }\n}","preventionTips":["Only undo entries that show an operation in `mise dot history`","Stop undoing at the first non-operation entry","Do not pass snapshot/protective checkpoint ids to undo"],"tags":["dotfiles","history","undo"],"backgroundTag":"unsupported-operation","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}