{"record":{"id":"56a574c215ec311d","repo":"jdx/mise","slug":"history-changed-during-the-operation-cannot-repla","errorCode":null,"errorMessage":"history changed during the operation; cannot replace its before state","messagePattern":"history changed during the operation; cannot replace its before state","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/checkpoint/preimages.rs","lineNumber":24,"sourceCode":"    pub(crate) fn protect_manual_preimage(\n        &self,\n        before: &str,\n        tracked: &TrackedSet,\n        path: &Path,\n        prior: &PathSnapshot,\n        previous: &[JournalEntry],\n    ) -> Result<Option<Box<Entry>>> {\n        let _lock = self.lock()?;\n        let repo = self\n            .repo\n            .as_ref()\n            .ok_or_else(|| eyre::eyre!(\"Git is unavailable\"))?;\n        let mut checkpoint = repo.read_meta(before)?;\n        let tree = repo.output_tree_of(before)?;\n        let head = repo\n            .ref_oid(HistoryRepo::HISTORY_REF)?\n            .ok_or_else(|| eyre::eyre!(\"history branch disappeared\"))?;\n        eyre::ensure!(\n            repo.output_tree_of(&head)? == tree,\n            \"history changed during the operation; cannot replace its before state\"\n        );\n        let mut promotion = Promotion {\n            store: self,\n            repo,\n            tracked,\n            previous,\n            overlays: BTreeMap::new(),\n            modes: checkpoint.tree.modes.clone(),\n        };\n        promotion.snapshot(path, prior, &tree)?;\n        if promotion.overlays.is_empty() && promotion.modes == checkpoint.tree.modes {\n            return Ok(None);\n        }\n        let overlays: Vec<_> = promotion\n            .overlays\n            .into_iter()","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/history/checkpoint/preimages.rs#L6-L42","documentation":"mise's manual preimage protection verifies that the history repository's tip still points at the same tree as the recorded 'before' checkpoint. If the history branch advanced (or changed) between reading the meta and the replacement, the before state can no longer be safely swapped out, so mise aborts. This is a concurrency safety check to prevent clobbering another process's history writes.","triggerScenarios":"Calling protect_manual_preimage when another mise process (or hook) has committed new entries to the history branch between reading the checkpoint meta and attempting the replace; or the history ref disappeared/moved.","commonSituations":"Running history-modifying commands concurrently in multiple shells/terminals with the same MISE_DATA_DIR; CI and local runs sharing a history store; a crash-recovery pass racing a user command.","solutions":["Re-run the command so it reads a fresh 'before' checkpoint and retries atomically","Ensure only one mise process mutates history at a time (close other shells using the same data dir)","Check for hooks, watchers, or scheduled tasks writing to the history repo","Clear or repair the history ref if it points to an unexpected commit (mise history repair/reset)"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// before replacing: confirm the history tip still matches\nlet head = repo.ref_oid(HistoryRepo::HISTORY_REF)?.ok_or_else(|| eyre::eyre!(\"history branch disappeared\"))?;\nif repo.output_tree_of(&head)? != tree { return Err(eyre::eyre!(\"history changed; re-read before state\")); }","typeGuard":null,"tryCatchPattern":"match err.message() { m if m.contains(\"history changed during the operation\") => re_read_checkpoint_and_retry(), _ => return Err(err) }","preventionTips":["Don't run concurrent mise commands that mutate history in the same data dir","Use file/branch locking around history mutations in scripts","Re-read the checkpoint state on each attempt instead of caching it"],"tags":["git","concurrency","history","state-conflict"],"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"}