jdx/mise · error
{} changed during recovery; left untouched
Error message
{} changed during recovery; left untouched What it means
recover_step restores a file's pre-image after a partially applied sync step. Before restoring it checks the live content still equals the pending 'object' and the permissions equal the desired mode; if the file was modified concurrently, recovery refuses to overwrite it and leaves the file untouched.
Source
Thrown at src/system/history/sync/apply.rs:666
}
if !req.automatic {
info!("history: applied {written} incoming change(s)");
}
let outcome = ApplyOutcome {
written,
held: held.len(),
configuration,
};
Ok(outcome)
}
fn recover_step(repo: &crate::system::history::shadow::HistoryRepo, step: &Step) -> Result<()> {
let current = live_object(repo, &step.path)?;
if current == step.before && live_permissions(&step.path)? == step.before_mode {
return Ok(());
}
if current != step.pending.object || live_permissions(&step.path)? != step.desired_mode {
bail!(
"{} changed during recovery; left untouched",
display_path(&step.path)
);
}
match &step.before {
Some((mode, oid)) => {
#[cfg(unix)]
let bits = {
use std::os::unix::fs::PermissionsExt;
step.permissions.as_ref().map(|p| p.mode() & 0o777)
};
#[cfg(not(unix))]
let bits = None;
replay::write_path_with_mode(repo, &step.path, mode, oid, bits)?;
}
None => replay::remove(&step.path)?,
}
if !step.path.is_symlink()View on GitHub (pinned to afd2eddd3a)
Solutions
- Review the file's current contents, then manually restore or discard changes and re-run the pull.
- Stop the process holding/writing the file and retry recovery.
- Commit or back up the concurrent edit before re-running sync.
Defensive patterns
Strategy: try-catch
Validate before calling
let current = live_object(repo, &step.path)?;
if current == step.pending.object {
// safe to recover
} Try / catch
match apply_result {
Err(e) if e.to_string().contains("changed during recovery") => {
// inspect and manually reconcile the file, then retry
}
other => other?,
} Prevention
- Close editors and stop processes holding tracked files during pulls
- Save or commit concurrent edits before running recovery
- Avoid mixing manual edits with in-flight sync operations
When it happens
Trigger: Calling apply (or recovery) while the target file is being edited; the live file's bytes or mode differ from step.pending.object / step.desired_mode at recovery time.
Common situations: An editor or another process saved the file between apply and recovery; a partially applied pull left the file in a state a running app modified; permissions changed via chmod.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- changed while preparing recovery; left untouched
- changed after the operation; left untouched
- a parent directory is now a symlink; left untouched
- invalid recovery content file
- local files were saved after enrollment planning; retry pull
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/d6b180ba270ea19d.
Report an issue: GitHub.