jdx/mise · error
interrupted file recovery needs attention; temporary…
Error message
interrupted file recovery needs attention; temporary recovery data was retained. {}. Run `mise dot recover` to retry, or inspect the files and use `recover <operation> --keep-current` to explicitly accept their current contents What it means
recover_entries attempts to restore each path from an interrupted write operation. When any individual path recovery fails, it collects the per-path failures and bails, retaining the temporary recovery data so nothing is lost, and tells the user to run `mise dot recover` or accept current contents with `recover <operation> --keep-current`.
Solutions
- Run `mise dot recover` to retry recovery of the retained data.
- For each listed failing path, compare the file against the intended content; if the current content is acceptable, run `mise dot recover <operation> --keep-current` to accept it explicitly.
- Inspect the recovery/temp data referenced by the error for files that need manual copying back into place.
- If files were changed intentionally, resolve path-by-path: restore expected content manually then re-run recover, or keep-current per operation.
Example fix
// before: fails with retained temp data $ mise dot status # shows unfinished recovery // after $ mise dot recover # retry $ mise dot recover <operation> --keep-current # accept current contents
Defensive patterns
Strategy: try-catch
Validate before calling
export function hasUnfinishedRecovery(statusOutput: string): boolean {
return /unfinished|pending recovery/i.test(statusOutput);
}
// run `mise dot status` before writes that could be interrupted Try / catch
try {
await dotRecover();
} catch (e) {
if (/interrupted file recovery needs attention/.test(String(e))) {
// temp data retained; resolve per listed path
for (const p of listedPaths(String(e))) reviewOrKeepCurrent(p);
await dotRecover();
} else throw e;
} Prevention
- Avoid killing mise during dotfile operations (use graceful termination)
- Run `mise dot status` after crashes to detect unfinished recovery early
- Keep other editors/sync tools from racing dotfile writes
When it happens
Trigger: recover_entries (via recover or recover_unfinished) iterates pending recovery entries and one or more recover_path calls return Err — e.g. the live file changed since the operation, the write completion was never recorded, a directory's contents could not be verified, or the snapshot validation failed.
Common situations: A mise process was killed mid dotfile write (power loss, Ctrl-C, OOM) leaving an unfinished recovery journal; on retry, the user or another tool edited the affected files so the recorded snapshots no longer match; the recovery store is partially corrupt.
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
- changed after the operation; left untouched
- changed while preparing recovery; left untouched
- cannot safely change
- directory contents cannot be verified safely; left untouched
- {}
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/7bd17f69ba2acf9e.
Report an issue: GitHub.
Appendix: source
Thrown at src/system/history/recovery.rs:56
continue;
}
let after = journal.iter().rev().find_map(|entry| match entry {
JournalEntry::Committed {
seq: recorded,
after,
} if *recorded as usize == seq => Some(after),
_ => None,
});
if unfinished_only && after.is_some() {
continue;
}
if let Err(error) = recover_path(state_dir, path, prior, after) {
blocked.push(path);
failures.push(format!("{}: {error:#}", crate::file::display_path(path)));
}
}
if !failures.is_empty() {
bail!(
"interrupted file recovery needs attention; temporary recovery data was retained. {}. Run `mise dot recover` to retry, or inspect the files and use `recover <operation> --keep-current` to explicitly accept their current contents",
failures.join("; ")
);
}
Ok(())
}
fn recover_path(
state_dir: &Path,
path: &Path,
prior: &PathSnapshot,
after: Option<&PathState>,
) -> Result<()> {
validate_destination(path)?;
let comparison = tempfile::tempdir()?;
let depth = if matches!(prior, PathSnapshot::Directory { .. }) {
Capture::Shallow
} else {View on GitHub (pinned to 533346cc37)