jdx/mise · error
checkpoint did not finish; there is no state to roll back to
Error message
checkpoint {} did not finish; there is no state to roll back to What it means
Rollback refuses checkpoints that are still marked Pending: their recorded state is not final, so rolling back to them would restore an indeterminate state. The checkpoint id is valid but unusable until the operation that created it completes.
Solutions
- Wait for the operation that created the checkpoint to finish, then retry the rollback.
- If the creating process is dead, remove/clean the stale checkpoint from the history store and use an earlier completed checkpoint.
- Use a different, completed checkpoint id as the rollback target.
Defensive patterns
Strategy: validation
Validate before calling
mise history list | jq 'select(.id == "<id>") | .status' # must not be "pending"
Prevention
- Roll back only to checkpoints with a completed status.
- Clean stale entries after crashed operations.
- Avoid killing mise processes that are checkpointing.
When it happens
Trigger: `mise history rollback <id>` where Entry.checkpoint.status() == Some(OperationStatus::Pending) in refuse_unusable.
Common situations: A previous mise operation (install, task run with checkpointing) crashed or is still running; stale Pending entries left after a killed process.
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
- appeared after was protected; nothing more was changed
- cannot retain an unreadable plaintext version of newly…
- changed after it was protected; nothing more was changed
- checkpoint has no content snapshot
- checkpoint was written by a newer mise (schema )
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/11d0fa5e44c22f8c.
Report an issue: GitHub.
Appendix: 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 533346cc37)