{"record":{"id":"e2da3369a4a9f6c1","repo":"jdx/mise","slug":"incoming-files-changed-while-preparing-adoption-p","errorCode":null,"errorMessage":"incoming files changed while preparing adoption; plan again","messagePattern":"incoming files changed while preparing adoption; plan again","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/sync/graph.rs","lineNumber":61,"sourceCode":"            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()\n                } else {\n                    repo.commit_tree(tree, vec![local, remote], \"merge origin dotfiles\")?\n                }\n            }\n        };\n        Ok(Some(Candidate {","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/history/sync/graph.rs#L43-L79","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Re-fetch origin and rebuild the adoption plan against the latest remote tree.","Retry the adoption after the concurrent push completes.","Coordinate pushes so only one machine publishes at a time (or re-run pull immediately before adopting)."],"exampleFix":"# before: plan from stale origin state\n$ mise bootstrap dotfiles pull   # fails: incoming files changed\n# after: refetch and re-plan\n$ git -C ~/.local/share/mise/history fetch origin\n$ mise bootstrap dotfiles pull","handlingStrategy":"retry","validationCode":"if repo.output_tree_of(remote_commit)? != planned_tree {\n    eprintln!(\"origin tree advanced; refetch and replan adoption\");\n}","typeGuard":null,"tryCatchPattern":"match candidate(plan, repo, &tree) {\n    Ok(c) => adopt(c),\n    Err(e) if e.to_string().contains(\"plan again\") => {\n        fetch_origin()?;\n        replan_and_adopt(repo)\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Fetch origin immediately before planning adoption.","Coordinate with other machines to avoid concurrent pushes.","Retry adoption promptly rather than leaving plans open during long interactions."],"tags":["race-condition","concurrency","git","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-14T05:17:10.506Z"}