{"record":{"id":"2ef80807aee756b1","repo":"jdx/mise","slug":"changed-during-setup-adoption-retry-pull","errorCode":null,"errorMessage":"{} changed during setup adoption; retry pull","messagePattern":"(.+?) changed during setup adoption; retry pull","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/sync/apply.rs","lineNumber":548,"sourceCode":"                    replay::write_path_with_mode(repo, &step.path, mode, oid, step.desired_mode)?\n                }\n                None => replay::remove(&step.path)?,\n            }\n            journal::commit_changes(pending);\n            let mut next = step.pending.next.clone();\n            let oid = step.pending.object.clone();\n            next.applied = oid.clone();\n            next.acknowledged = oid;\n            sync_state.insert(step.pending.branch_path.clone(), next);\n        }\n        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","sourceCodeStart":530,"sourceCodeEnd":566,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/history/sync/apply.rs#L530-L566","documentation":"After writing the whole application batch but before advancing Git (adopting the setup), mise re-reads every written file and compares it against the pending object and desired permissions. If any file drifted during the write phase, Git is not advanced and the error names the changed path, asking for a pull retry — a concurrent edit must never be recorded as an applied setup.","triggerScenarios":"Post-write verification: `live_object(repo, step.path) != step.pending.object || live_permissions(&step.path) != step.desired_mode` for any step — the file was modified (or its mode changed) after being written but before the history ref advanced.","commonSituations":"A watcher or editor rewrote a file immediately after mise wrote it; another sync process overwrote the file during the batch; permissions altered by an external chmod or umask-sensitive tool between write and verification.","solutions":["Re-run `mise bootstrap dotfiles pull` — the retry recomputes the plan from the current tree and re-adopts cleanly.","Identify and stop the concurrent writer (editors, watchers, second sync processes) before retrying.","If the drift is only permissions, set the expected mode (chmod) or let the retry plan recompute the desired mode, then pull again."],"exampleFix":"# before: drift between write and git advance\nmise bootstrap dotfiles pull   # -> \"changed during setup adoption; retry pull\"\n# after\nmise bootstrap dotfiles pull   # retry recomputes and adopts","handlingStrategy":"retry","validationCode":"# stop background watchers that rewrite dotfiles before pulling\nmise bootstrap dotfiles pull --dry-run   # confirm plan, then apply without interference","typeGuard":null,"tryCatchPattern":"try {\n  await pull();\n} catch (e) {\n  if (/changed during setup adoption/.test(e.message)) {\n    await pauseWatchers();\n    return await pull(); // retry recomputes and adopts cleanly\n  }\n  throw e;\n}","preventionTips":["Pause file watchers/daemons that touch tracked dotfiles during a pull.","Avoid running two sync operations concurrently; the sync lock covers mise only.","After a failed adoption, always retry with a fresh pull instead of manually editing state."],"tags":["sync","concurrency","race-condition","verification","retry"],"backgroundTag":"checksum-mismatch","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"}