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
- Read the embedded `reason` in the message to learn why the preimage was not recorded.
- Accept the file's current contents with `recover <operation> --keep-current`, or restore the desired content manually from your dotfiles repo.
- 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
- Ensure target files are readable and within capture size limits before running write operations
- Keep a VCS or backup of dotfiles so unrecorded preimages can be restored manually
- Read the embedded reason in the message to understand why capture was skipped
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
- cannot safely change {} without a recovery preimage: {reason
- recovery directory descends through a file or symlink
- brew-cask: unresolved recovery for {} still preserves its or
- brew-cask: unresolved recovery for newly created target {}
- brew-cask: refusing to restore flight target through a chang
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/9e943e4afd1566cb.
Report an issue: GitHub.