{"record":{"id":"649f2480150ac146","repo":"jdx/mise","slug":"setup-history-changed-during-adoption-retry-pull","errorCode":null,"errorMessage":"setup history changed during adoption; retry pull","messagePattern":"setup history changed during adoption; retry pull","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/sync/apply.rs","lineNumber":559,"sourceCode":"        if fresh_adoption || inventory_tree.is_some() {\n            // Verify the whole written batch again before advancing Git. A\n            // concurrent edit must not become an apparently applied setup.\n            for step in &ready {\n                if live_object(repo, &step.path)? != step.pending.object\n                    || live_permissions(&step.path)? != step.desired_mode\n                {\n                    bail!(\n                        \"{} changed during setup adoption; retry pull\",\n                        display_path(&step.path)\n                    );\n                }\n            }\n            for directory in &directories {\n                directory.verify_written()?;\n            }\n            let heads = super::graph::Heads::read(repo)?;\n            if heads.local != application_head || heads.remote != status.upstream_commit {\n                bail!(\"setup history changed during adoption; retry pull\");\n            }\n            let remote = heads.remote.as_deref().unwrap();\n            super::files::audit_history(repo, remote, &Default::default())?;\n            let tree = inventory_tree\n                .clone()\n                .unwrap_or(repo.output_tree_of(remote)?);\n            let candidate = heads\n                .candidate(repo, &tree)?\n                .ok_or_else(|| eyre::eyre!(\"setup branch disappeared during adoption\"))?;\n            candidate.adopt(repo)?;\n        }\n        Ok(())\n    })();\n    if let Err(error) = &result {\n        let mut recovery_errors = vec![];\n        for step in ready\n            .iter()\n            .rev()","sourceCodeStart":541,"sourceCodeEnd":577,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/history/sync/apply.rs#L541-L577","documentation":"During a setup-history sync pull, the apply routine verifies that the repository heads still match what was observed when the adoption plan was built. If the local or remote head moved between planning and commit, the operation is aborted to avoid adopting a history that no longer matches reality. The message instructs the user to retry, since a fresh pull will re-read current heads.","triggerScenarios":"Concurrent commit of setup history (another mise process or a manual git commit into the history repo) between reading heads and verifying them in apply; a background push/pull moved heads.remote.","commonSituations":"Running mise sync/pull in two terminals at once; a cron or IDE plugin committing history during a pull; a user manually editing the history repo while a pull runs.","solutions":["Re-run the pull command; the retry re-plans against current heads.","Identify the concurrent writer (another mise session, script, or manual git command) and stop it before pulling.","If heads moved unintentionally, inspect the history repo refs and reconcile before retrying."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"let heads = Heads::read(repo)?;\nif heads.local != application_head || heads.remote != upstream_commit {\n    // heads moved; re-plan instead of applying\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run only one mise history sync at a time","Avoid committing to the history repo manually during pulls","Retry the pull immediately; it is designed to converge"],"tags":["git","concurrency","sync","race-condition"],"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"}