jdx/mise · error
origin changed while planning; reconcile again
Error message
origin changed while planning; reconcile again
What it means
During `prepare`, mise plans the directory changes against a snapshot of the upstream. After planning, it re-checks that the remote head (`heads.remote`) still equals the upstream commit it planned against; if the origin moved mid-operation (another machine pushed while this sync was planning), the plan is stale and mise aborts, asking for a fresh reconciliation. This is a deliberate optimistic-concurrency check.
Source
Thrown at src/system/history/sync/run.rs:678
// turn an ordinary incoming edit into an unrelated adoption conflict.
let heads = super::graph::Heads::read(repo)?;
status.upstream_commit = heads.remote.clone();
status.pending_repository = match &heads.local {
Some(local) => {
crate::system::history::manifest::Manifest::read(repo, local)?.as_ref()
!= Some(&tracked.manifest)
}
None => heads.remote.is_some(),
};
let repository_tree = incoming_repository_tree(repo, tracked)
.inspect_err(|error| repository_conflict(status, error))?;
status.pending_repository |= repository_tree.is_some();
if let Some(tree) = repository_tree.as_deref().or(heads.remote.as_deref()) {
super::directories::plan(repo, tracked, tree)
.inspect_err(|error| repository_conflict(status, error))?;
}
if heads.remote != upstream.commit {
bail!("origin changed while planning; reconcile again");
}
let baseline = reconcile::upstream(repo, heads.base.as_deref())?;
let local_manifest = heads
.local
.as_deref()
.map(|head| crate::system::history::manifest::Manifest::read(repo, head))
.transpose()?
.flatten()
.unwrap_or_default();
let sync_state: state::SyncState = baseline
.files
.into_iter()
.map(|(path, object)| {
(
path,
state::SyncRecord {
acknowledged: Some(object.clone()),
reconciled: Some(object.clone()),View on GitHub (pinned to afd2eddd3a)
Solutions
- Simply re-run `mise bootstrap dotfiles sync` — it fetches the new head and replans from scratch
- Ensure only one sync runs at a time (see the status-lock) so competing machines don't interleave
- If another machine is the mover, coordinate pushes/pulls rather than syncing simultaneously
Defensive patterns
Strategy: retry
Try / catch
catch (e) { if (String(e).includes('origin changed while planning')) { return syncAgain(); } throw e; } Prevention
- Avoid running sync on two machines against the same branch simultaneously
- Keep sync operations short so the plan window is small
When it happens
Trigger: `mise bootstrap dotfiles sync` (or `refresh_with_interaction`) where, between the fetch and the end of planning (`super::directories::plan`), the remote branch advanced so `heads.remote != upstream.commit`.
Common situations: Another machine or CI pushed to the setup branch during a long local sync; a background scheduled sync raced an interactive one; network flakiness causing re-fetch of a moved ref mid-run.
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
- setup history changed during adoption; retry pull
- incoming files changed while preparing adoption; plan again
- local saved history changed while planning; reconcile again
- origin changed while preparing publication; reconcile again
- {} changed before application; nothing was written
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/1b6e5eb46b44df45.
Report an issue: GitHub.