jdx/mise · error

saved files changed while preparing publication; plan again

Error message

saved files changed while preparing publication; plan again

What it means

candidate() plans the publication of locally saved files. It re-checks that the local commit's output tree still equals the tree the caller captured when planning. If the saved files changed between planning and applying, the plan is stale and applying it would lose changes, so it aborts and asks the caller to plan again.

Source

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

                (bases.len() == 1).then(|| bases[0].clone())
            }
            _ => None,
        };
        Ok(Self {
            local,
            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()

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Re-run the sync/publication planning step so a fresh tree snapshot is captured.
  2. Close other processes writing to the dotfiles, then retry the sync.
  3. Commit or revert pending local changes before starting the publication flow.

Example fix

// before: plan built, then files change, then apply
let plan = plan(repo, tree)?; /* files change here */ apply(repo, plan)?;
// after: rebuild the plan immediately before applying
let plan = plan(repo, current_tree(repo)?)?;
apply(repo, plan)?;
Defensive patterns

Strategy: retry

Validate before calling

if repo.output_tree_of(local_commit)? != planned_tree {
    eprintln!("local tree drifted; replan before publishing");
}

Try / catch

match candidate(plan, repo, &tree) {
    Ok(c) => apply(c),
    Err(e) if e.to_string().contains("plan again") => {
        eprintln!("state changed; replanning");
        replan_and_apply(repo)
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling candidate() with (local, remote)=(Some, None) where repo.output_tree_of(local) != the tree argument — i.e. local saved files were modified/committed after the plan was built.

Common situations: Another process (editor, another mise invocation, a second terminal) wrote dotfiles while a sync/publication was being prepared; a long-running interactive prompt during which files changed; an automated job committing to the store 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/f2333f07134cb310. Report an issue: GitHub.