{"record":{"id":"f3150262d0aad257","repo":"jdx/mise","slug":"path-s-conflict-see-the-plan-above-resolve","errorCode":null,"errorMessage":"{} path(s) conflict (see the plan above); resolve them first{hint}","messagePattern":"(.+?) path\\(s\\) conflict \\(see the plan above\\); resolve them first(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/replay.rs","lineNumber":420,"sourceCode":"        return Ok(());\n    }\n    let conflicts: Vec<&Step> = steps\n        .iter()\n        .filter(|step| matches!(step.action, Action::Conflict(_)))\n        .collect();\n    if !conflicts.is_empty() {\n        // `--force` answers a type change only (and undo already forces);\n        // an occupant history never captured stays a conflict whatever is\n        // passed, so it is not offered where it would not help\n        let type_changes = conflicts.iter().any(\n            |step| matches!(&step.action, Action::Conflict(reason) if reason.contains(\" became \")),\n        );\n        let hint = if !exec.force && type_changes {\n            \"; pass --force to replace a path whose type changed\"\n        } else {\n            \"\"\n        };\n        bail!(\n            \"{} path(s) conflict (see the plan above); resolve them first{hint}\",\n            conflicts.len()\n        );\n    }\n    // a link to a directory is not the directory: it counts as work left\n    let restores = exec\n        .restore_dirs\n        .iter()\n        .filter(|dir| std::fs::symlink_metadata(dir).is_err())\n        .count();\n    if !steps.iter().any(|step| step.action.mutates()) && restores == 0 {\n        info!(\"history: nothing to do\");\n        return Ok(());\n    }\n    if !exec.yes && !prompt::confirm(\"history: apply this plan?\")?.is_yes() {\n        info!(\"history: skipped\");\n        return Ok(());\n    }","sourceCodeStart":402,"sourceCodeEnd":438,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/history/replay.rs#L402-L438","documentation":"Before applying a restore plan, execute checks for conflicts (e.g. a tracked symlink now exists as a real directory or file — the path's type changed). If any conflicts remain and `--force` was not passed, the whole operation aborts so the user can review the printed plan first.","triggerScenarios":"`execute` (rollback/undo) finds `conflicts` non-empty while `exec.force` is false and the conflict is a changed path type — e.g. the tracked entry was a symlink but the live path is now a directory.","commonSituations":"A tool replaced a dotfile symlink with a real directory (or vice versa) after tracking; reinstalling an app that overwrites managed dotfiles; running rollback without `--force` after manual restructuring of config directories.","solutions":["Review the printed plan, resolve the conflicts manually (remove/rename the changed paths), then re-run rollback/undo","Re-run with `--force` to replace paths whose type changed: `mise dot rollback --to <ref> --all --force`","Back up the conflicting path first if it may contain data, then force or delete it"],"exampleFix":"// before\nmise dot rollback --to checkpoint-42 --all\n# error: 1 path(s) conflict\n// after\nmise dot rollback --to checkpoint-42 --all --force","handlingStrategy":"validation","validationCode":"const plan = await mise.dot.plan(req); // hypothetical dry-run\nif (plan.conflicts.length > 0 && !req.force) {\n  throw new Error('resolve conflicts or pass --force');\n}","typeGuard":null,"tryCatchPattern":"try {\n  await mise.dot.rollback(req);\n} catch (e) {\n  if (/path\\(s\\) conflict/.test(e.message) && !req.force) {\n    req.force = true; // after reviewing/backing up\n  }\n}","preventionTips":["Back up changed-type paths before forcing","Check that tracked symlinks haven't been replaced by real dirs before rollback","Use --force deliberately, never by default in scripts"],"tags":["dotfiles","conflict","filesystem"],"backgroundTag":"conflicting-config-options","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"}