jdx/mise · error
local saved history changed since planning; nothing was appl
Error message
local saved history changed since planning; nothing was applied; run pull again
What it means
validate_starting_head compares the head recorded when the plan was made against the current saved history head. If local saved history changed since planning, applying the plan could land on an unexpected base, so mise aborts with nothing applied and asks the user to pull again.
Source
Thrown at src/system/history/scope.rs:238
warn!("history: could not persist the capture label: {err:#}");
}
}
}
/// The protective checkpoint this operation took, if any.
pub(crate) fn before(&self) -> Option<(u64, String)> {
self.0
.as_ref()
.and_then(|shared| lock_unpoisoned(shared).before.clone())
}
pub(crate) fn validate_starting_head(&self, expected: Option<&str>) -> Result<()> {
let Some(shared) = &self.0 else {
eyre::bail!("incoming application requires an active recovery operation");
};
let writer = lock_unpoisoned(shared);
if writer.starting_head.as_deref() != expected {
eyre::bail!(
"local saved history changed since planning; nothing was applied; run pull again"
);
}
Ok(())
}
/// Retakes the protective checkpoint, replacing the earlier one, when
/// files changed between it and the verified plan.
pub(crate) fn recapture_before(&self, paths: &[PathBuf]) -> Result<()> {
let Some(shared) = &self.0 else {
return Ok(());
};
let mut writer = lock_unpoisoned(shared);
// held across the reservation, the capture, and the removal: the
// capture writes the index and a checkpoint ref, which a concurrent
// `mise bootstrap dotfiles save` must not interleave with
let _store_lock = writer.store.lock()?;
let previous = writer.before.take();View on GitHub (pinned to afd2eddd3a)
Solutions
- Run pull again so a fresh plan is generated against the current head
- Avoid running other history operations concurrently with pull
- If conflicts are frequent, serialize history operations across machines/shells
Example fix
// before mise pull # plan created; local history changed meanwhile → error // after mise pull # rerun: fresh plan against current head
Defensive patterns
Strategy: retry
Validate before calling
let current_head = history.head();
if Some(current_head.as_deref()) != planned_starting_head.as_deref() {
eprintln!("history changed since planning; replan (pull again)");
} Try / catch
match apply_incoming() {
Err(e) if e.to_string().contains("run pull again") => pull_fresh_and_apply(),
other => other,
} Prevention
- Do not run concurrent history operations while pulling
- Re-pull after any local rollback/commit made mid-plan
- One state dir per machine/shell workflow
When it happens
Trigger: writer.starting_head.as_deref() != expected: another history operation committed/rolled back between planning the incoming apply and executing it.
Common situations: Two machines or two shells sharing a state dir apply history concurrently; a local rollback or commit happened after `pull` started; stale plan replayed after local history edits.
Related errors
- lockfile {} changed while the format upgrade was being prepa
- changed after the operation; left untouched
- the refreshed plan has conflicts; nothing was changed
- another history operation is running: {} since {} ({})
- another history operation is running
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/39276f27256eacdd.
Report an issue: GitHub.