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
- Re-run the sync/publication planning step so a fresh tree snapshot is captured.
- Close other processes writing to the dotfiles, then retry the sync.
- 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
- Minimize the window between planning and applying publication.
- Avoid editing dotfiles while a sync is running.
- Quiesce other mise instances/processes before publishing.
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
- {} changed before application; nothing was written
- {} changed while the changes were being applied; nothing mor
- {} changed during setup adoption; retry pull
- setup history changed during adoption; retry pull
- incoming files changed while preparing adoption; plan again
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/f2333f07134cb310.
Report an issue: GitHub.