jdx/mise · error

checkpoint {} has no content snapshot

Error message

checkpoint {} has no content snapshot

What it means

Planning a replay requires the checkpoint's content snapshot (checkpoint.tree.snapshot) to compute file-level diffs. If the referenced checkpoint entry has no snapshot, planning cannot proceed and mise throws this error with the checkpoint id.

Source

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

/// The plan for every selected path of every target.
fn repository_path(repo: &HistoryRepo, tree: &str, path: &Path) -> Result<String> {
    if let Some(manifest) = super::manifest::Manifest::read(repo, tree)? {
        let tracked = manifest.tracking()?;
        if let Some(entry) = tracked.entry_for(&normalize_target(path)) {
            return entry.tree_path(&normalize_target(path));
        }
    }
    Ok(display_to_tree_path(&path.to_string_lossy()))
}

fn plan(repo: &HistoryRepo, exec: &Execution, live: &str) -> Result<Vec<Step>> {
    let force = exec.force;
    let mut steps = vec![];
    for target in &exec.targets {
        let checkpoint = &target.entry.checkpoint;
        let Some(snapshot) = &checkpoint.tree.snapshot else {
            bail!("checkpoint {} has no content snapshot", target.entry.id);
        };
        for path in &target.paths {
            let tree_path = repository_path(repo, live, path)?;
            let mut files: BTreeSet<String> = BTreeSet::new();
            let mut live_files: BTreeSet<String> = BTreeSet::new();
            let mut snapshot_files: BTreeSet<String> = BTreeSet::new();
            // nested repositories in either tree: what is inside one is its
            // own, never written into or removed by a rollback
            let mut gitlinks: BTreeSet<String> = BTreeSet::new();
            for tree in [snapshot.as_str(), live] {
                let selected = repository_path(repo, tree, path)?;
                match repo.object_at(tree, &selected)? {
                    Some((mode, _)) if mode == "040000" => {
                        for entry in repo.ls_tree(&format!("{tree}:{selected}"))? {
                            let file = format!("{tree_path}/{}", entry.path);
                            if entry.mode == "160000" {
                                gitlinks.insert(file.clone());
                            }

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. List checkpoints (`mise history`) and target one that includes a content snapshot
  2. Use `refuse_unusable`-style checks: pick a checkpoint with a non-pending status and a snapshot
  3. If the checkpoint should have a snapshot, the store may be corrupted — recreate/re-record the checkpoint
Defensive patterns

Strategy: validation

Validate before calling

// select only checkpoints that have a content snapshot
let usable: Vec<_> = entries.into_iter()
    .filter(|e| e.checkpoint.tree.snapshot.is_some())
    .collect();

Type guard

fn has_snapshot(e: &Entry) -> bool {
    e.checkpoint.tree.snapshot.is_some()
}

Prevention

When it happens

Trigger: `mise history` replay/rollback targets a checkpoint entry whose tree.snapshot is None — plan() iterates exec.targets and bails on the first snapshotless entry.

Common situations: Targeting an operation checkpoint that only recorded metadata (e.g. a command that never captured file contents); a truncated or partially-written checkpoint; internal checkpoints that don't snapshot trees.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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