jdx/mise · error

no usable preimage: {reason}

Error message

no usable preimage: {reason}

What it means

When the recorded preimage is PathSnapshot::Unrecorded, the journal explicitly states that the path's prior content was never captured (with a reason), so there is nothing to restore. validate_snapshot bails early with that reason instead of attempting a restore. This is informational-by-design: recovery cannot undo a write whose original state is unknown.

Source

Thrown at src/system/history/recovery.rs:188

                }
            }
            for leaf in files
                .iter()
                .map(|f| &f.rel)
                .chain(links.iter().map(|f| &f.rel))
            {
                if seen
                    .iter()
                    .any(|other| *other != leaf && other.starts_with(leaf))
                {
                    bail!("recovery directory descends through a file or symlink");
                }
            }
            for file in files {
                read_blob(state_dir, &file.content)?;
            }
        }
        PathSnapshot::Unrecorded { reason, .. } => bail!("no usable preimage: {reason}"),
        _ => {}
    }
    Ok(())
}

fn remove_leaf(path: &Path) -> Result<()> {
    match std::fs::symlink_metadata(path) {
        Ok(meta) if meta.is_dir() => std::fs::remove_dir(path)?,
        Ok(_) => std::fs::remove_file(path)?,
        Err(error) if error.kind() == std::io::ErrorKind::NotFound => {}
        Err(error) => return Err(error.into()),
    }
    Ok(())
}

fn set_mode(path: &Path, mode: u32) -> Result<()> {
    #[cfg(unix)]
    {

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Read the embedded `reason` in the message to learn why the preimage was not recorded.
  2. Accept the file's current contents with `recover <operation> --keep-current`, or restore the desired content manually from your dotfiles repo.
  3. For future operations, ensure target files are readable and within capture limits so preimages get recorded.

Example fix

// before
error: ~/.config/large.bin: no usable preimage: preimage exceeded capture size limit

// after (accept current contents)
$ mise bootstrap dotfiles recover <operation> --keep-current
Defensive patterns

Strategy: try-catch

Validate before calling

// inspect the snapshot variant before recovery to know if rollback is possible
if matches!(prior, PathSnapshot::Unrecorded { .. }) {
    eprintln!("no preimage recorded; rollback impossible -- plan manual restore");
}

Try / catch

match recover(&state_dir, &journal) {
    Err(e) if e.to_string().contains("no usable preimage") => {
        // accept current contents: mise bootstrap dotfiles recover <op> --keep-current
    }
    other => other?,
}

Prevention

When it happens

Trigger: recover_path -> validate_snapshot on a prior snapshot of variant Unrecorded { reason, .. } — the write operation intentionally skipped preimage capture (e.g. preimage too large, unreadable, or excluded by policy at operation time).

Common situations: The original write hit a file that was unreadable or excluded from capture when the operation ran; running recovery later for that operation finds no preimage to roll back to.

Related errors


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