{"record":{"id":"cd3256b97895bb03","repo":"jdx/mise","slug":"these-paths-keep-changing-while-being-protected-n","errorCode":null,"errorMessage":"these paths keep changing while being protected; nothing was changed: {}","messagePattern":"these paths keep changing while being protected; nothing was changed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/replay.rs","lineNumber":533,"sourceCode":"            .checkpoint\n            .tree\n            .snapshot\n            .clone()\n            .ok_or_else(|| eyre::eyre!(\"the protective checkpoint has no content\"))?;\n        let mut missing = vec![];\n        for step in steps.iter().filter(|step| step.action.mutates()) {\n            let Some(current) = repo.restored_object_at(&live, &step.tree_path)? else {\n                continue;\n            };\n            if repo.restored_object_at(&before_tree, &step.tree_path)? != Some(current) {\n                missing.push(step.path.clone());\n            }\n        }\n        if missing.is_empty() {\n            break;\n        }\n        if round >= VERIFY_ROUNDS {\n            bail!(\n                \"these paths keep changing while being protected; nothing was changed: {}\",\n                missing\n                    .iter()\n                    .map(display_path)\n                    .collect::<Vec<_>>()\n                    .join(\", \")\n            );\n        }\n        warn!(\n            \"history: {} path(s) changed after the protective checkpoint; capturing again\",\n            missing.len()\n        );\n        scope.recapture_before(&missing)?;\n    }\n    let mut touched = vec![];\n    // deletions deepest first, then writes shallowest first: a directory is\n    // emptied before the file that replaces it is written, and a directory\n    // that replaces a file exists before its files are written","sourceCodeStart":515,"sourceCodeEnd":551,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/history/replay.rs#L515-L551","documentation":"After taking the protective checkpoint, mise re-verifies (up to VERIFY_ROUNDS rounds) that every path it is about to touch still matches what was captured. If paths keep appearing/changing between rounds, it cannot guarantee a consistent restore point and aborts. Nothing was changed.","triggerScenarios":"A set of target paths is repeatedly found missing or modified across verification rounds in apply_steps, exceeding VERIFY_ROUNDS — e.g. another process writes those files continuously while the rollback is being prepared.","commonSituations":"A dev server, watcher, build task, or editor actively writing files under the paths being restored; another concurrent mise run touching the same files.","solutions":["Stop the process writing those paths (watcher, dev server, running task), then re-run the rollback.","Exclude the churning paths from the restore scope, or restore a narrower set of stable files.","Check for a concurrent mise history/rollback process and wait for it to finish."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"fuser -v <target-paths> 2>/dev/null || echo \"no writers detected\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Stop watchers/dev servers before running history restores.","Run one history operation at a time; avoid concurrent rollback/undo.","Restore from a quiet tree (no active builds writing to targets)."],"tags":["history","concurrency","checkpoint","race-condition"],"backgroundTag":"concurrent-modification-detected","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}