{"record":{"id":"f2333f07134cb310","repo":"jdx/mise","slug":"saved-files-changed-while-preparing-publication-p","errorCode":null,"errorMessage":"saved files changed while preparing publication; plan again","messagePattern":"saved files changed while preparing publication; plan again","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/sync/graph.rs","lineNumber":55,"sourceCode":"                (bases.len() == 1).then(|| bases[0].clone())\n            }\n            _ => None,\n        };\n        Ok(Self {\n            local,\n            remote,\n            base,\n        })\n    }\n\n    /// Preparing a candidate does not advance a branch or write live files.\n    /// The caller must finish its complete application before adopting it.\n    pub(crate) fn candidate(&self, repo: &HistoryRepo, tree: &str) -> Result<Option<Candidate>> {\n        let commit = match (&self.local, &self.remote) {\n            (None, None) => return Ok(None),\n            (Some(local), None) => {\n                if repo.output_tree_of(local)? != tree {\n                    bail!(\"saved files changed while preparing publication; plan again\");\n                }\n                local.clone()\n            }\n            (None, Some(remote)) => {\n                if repo.output_tree_of(remote)? != tree {\n                    bail!(\"incoming files changed while preparing adoption; plan again\");\n                }\n                remote.clone()\n            }\n            (Some(local), Some(remote)) => {\n                if self.base.as_ref() == Some(remote) {\n                    if repo.output_tree_of(local)? != tree {\n                        bail!(\"saved files changed while preparing publication; plan again\");\n                    }\n                    local.clone()\n                } else if self.base.as_ref() == Some(local) && repo.output_tree_of(remote)? == tree\n                {\n                    remote.clone()","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/history/sync/graph.rs#L37-L73","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: plan built, then files change, then apply\nlet plan = plan(repo, tree)?; /* files change here */ apply(repo, plan)?;\n// after: rebuild the plan immediately before applying\nlet plan = plan(repo, current_tree(repo)?)?;\napply(repo, plan)?;","handlingStrategy":"retry","validationCode":"if repo.output_tree_of(local_commit)? != planned_tree {\n    eprintln!(\"local tree drifted; replan before publishing\");\n}","typeGuard":null,"tryCatchPattern":"match candidate(plan, repo, &tree) {\n    Ok(c) => apply(c),\n    Err(e) if e.to_string().contains(\"plan again\") => {\n        eprintln!(\"state changed; replanning\");\n        replan_and_apply(repo)\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Minimize the window between planning and applying publication.","Avoid editing dotfiles while a sync is running.","Quiesce other mise instances/processes before publishing."],"tags":["race-condition","concurrency","sync"],"backgroundTag":"invalid-state-transition","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}