jdx/mise · error

incoming files changed while preparing adoption; plan again

Error message

incoming files changed while preparing adoption; plan again

What it means

candidate() mirrors the local-side check for adoption: when only a remote commit exists, it verifies the remote commit's output tree still matches the tree captured when planning. If incoming files changed on origin between planning and applying, the adoption plan is stale and applying it could clobber newer incoming content, so it aborts.

Source

Thrown at src/system/history/sync/graph.rs:61

            remote,
            base,
        })
    }

    /// Preparing a candidate does not advance a branch or write live files.
    /// The caller must finish its complete application before adopting it.
    pub(crate) fn candidate(&self, repo: &HistoryRepo, tree: &str) -> Result<Option<Candidate>> {
        let commit = match (&self.local, &self.remote) {
            (None, None) => return Ok(None),
            (Some(local), None) => {
                if repo.output_tree_of(local)? != tree {
                    bail!("saved files changed while preparing publication; plan again");
                }
                local.clone()
            }
            (None, Some(remote)) => {
                if repo.output_tree_of(remote)? != tree {
                    bail!("incoming files changed while preparing adoption; plan again");
                }
                remote.clone()
            }
            (Some(local), Some(remote)) => {
                if self.base.as_ref() == Some(remote) {
                    if repo.output_tree_of(local)? != tree {
                        bail!("saved files changed while preparing publication; plan again");
                    }
                    local.clone()
                } else if self.base.as_ref() == Some(local) && repo.output_tree_of(remote)? == tree
                {
                    remote.clone()
                } else {
                    repo.commit_tree(tree, vec![local, remote], "merge origin dotfiles")?
                }
            }
        };
        Ok(Some(Candidate {

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Re-fetch origin and rebuild the adoption plan against the latest remote tree.
  2. Retry the adoption after the concurrent push completes.
  3. Coordinate pushes so only one machine publishes at a time (or re-run pull immediately before adopting).

Example fix

# before: plan from stale origin state
$ mise bootstrap dotfiles pull   # fails: incoming files changed
# after: refetch and re-plan
$ git -C ~/.local/share/mise/history fetch origin
$ mise bootstrap dotfiles pull
Defensive patterns

Strategy: retry

Validate before calling

if repo.output_tree_of(remote_commit)? != planned_tree {
    eprintln!("origin tree advanced; refetch and replan adoption");
}

Try / catch

match candidate(plan, repo, &tree) {
    Ok(c) => adopt(c),
    Err(e) if e.to_string().contains("plan again") => {
        fetch_origin()?;
        replan_and_adopt(repo)
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling candidate() with (local, remote)=(None, Some) where repo.output_tree_of(remote) != the tree argument — origin's saved files advanced after the plan was built.

Common situations: Another machine pushed to the origin store while this machine was preparing adoption; a slow interactive confirmation window during which a fetch brought in newer commits; scheduled CI pushing dotfile changes concurrently.

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


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/e2da3369a4a9f6c1. Report an issue: GitHub.