{"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/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/history/replay.rs#L402-L438","documentation":"Before executing a restore, execute() computes a plan and detects conflicts: paths whose current on-disk state diverges from what the restore expects (including type changes like file→symlink). If any conflicts exist and the request is not forced, mise aborts with the conflict count, a pointer to the printed plan, and — when a conflicting path's type changed and --force was not given — a hint to pass --force.","triggerScenarios":"execute (via rollback or undo) finds conflicts.len() > 0 and exec.force is false; the extra --force hint appears when type_changes is true. Typical causes: files edited locally after the checkpoint, symlink↔file swaps, different ownership/targets.","commonSituations":"User edited dotfiles since the checkpoint and now undoes; a tool replaced a symlink with a regular file (or vice versa); config managers (stow, chezmoi) changed link types.","solutions":["Review the printed plan, resolve the listed conflicting paths manually, then re-run","Re-run with --force to replace paths whose type changed: `... --force`","Commit or stash local edits so the restore can proceed cleanly, then rollback/undo"],"exampleFix":"// before\nmise bootstrap dotfiles undo          # 3 path(s) conflict, type changed\n// after\nmise bootstrap dotfiles undo --force  # accept replacement of type-changed paths","handlingStrategy":"try-catch","validationCode":"const plan = await previewPlan(req);\nif (plan.conflicts.length > 0) {\n  console.warn(plan.conflicts.join(\"\\n\"));\n  if (!force) throw new Error(\"conflicts present; pass --force\");\n}","typeGuard":"const isClean = (plan: Plan): plan is Plan & { conflicts: [] } =>\n  plan.conflicts.length === 0;","tryCatchPattern":"try {\n  await undo();\n} catch (e) {\n  if (String(e).includes(\"path(s) conflict\")) {\n    if (typeChangedConfirmed) {\n      await undo({ force: true });\n    } else {\n      console.error(\"Resolve conflicts shown in the plan first.\");\n    }\n  } else throw e;\n}","preventionTips":["Preview the plan/diff before rolling back or undoing","Commit or stash local dotfiles edits before restoring","Watch for symlink↔file type changes from other config managers","Use --force deliberately, only after reviewing the plan"],"tags":["conflict","restore","force"],"backgroundTag":"conflicting-config-options","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}