{"record":{"id":"af2a777318023f56","repo":"jdx/mise","slug":"choose-only-one-resolution-for","errorCode":null,"errorMessage":"choose only one resolution for {}","messagePattern":"choose only one resolution for (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/sync/apply.rs","lineNumber":148,"sourceCode":"        .iter()\n        .map(|path| normalize_target(path))\n        .collect();\n\n    // Store choices without publishing or applying any part of the setup.\n    let mut sync_state = state::load(repo)?;\n    let shared = super::share::current(repo, tracked)?.objects();\n    let encrypted = super::files::encrypted_paths(repo, status.upstream_commit.as_deref())?;\n    for conflict in &status.conflicts {\n        let Some(local) = roots\n            .locate(&conflict.branch_path)\n            .path()\n            .map(Path::to_path_buf)\n        else {\n            continue;\n        };\n        if take_remote.contains(&local) || keep_local.contains(&local) {\n            if take_remote.contains(&local) && keep_local.contains(&local) {\n                bail!(\"choose only one resolution for {}\", display_path(&local));\n            }\n            let live = live_object(repo, &local)?;\n            let saved = shared.get(&conflict.branch_path).cloned();\n            let saved_mode = permissions_at(\n                repo,\n                planned_head.as_deref(),\n                &conflict.branch_path,\n                saved.as_ref(),\n            )?;\n            if keep_local.contains(&local)\n                && (live != saved || live_permissions(&local)? != saved_mode)\n            {\n                bail!(\"save {} before choosing --keep-local\", display_path(&local));\n            }\n            let remote = match status.upstream_commit.as_deref() {\n                Some(head) => repo\n                    .object_at(head, &conflict.branch_path)?\n                    .map(|object| {","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/history/sync/apply.rs#L130-L166","documentation":"When resolving dotfiles sync conflicts, each conflicted path may receive exactly one resolution: either take the upstream (remote) version or keep the local version. This error is thrown by `mise bootstrap dotfiles pull --take-remote/--keep-local` when the same path appears in both lists, making the requested resolution ambiguous. It aborts before any state is changed, so no resolution is recorded.","triggerScenarios":"Running apply with the same normalized path in both req.take_remote and req.keep_local, e.g. `mise bootstrap dotfiles pull --take-remote ~/.zshrc --keep-local ~/.zshrc`. Paths are normalized first, so even different spellings of the same file collide.","commonSituations":"Shell history re-runs where a flag from a previous invocation is concatenated with a new one; scripted loops appending to both flag lists; copy-pasted commands combining both resolution styles; shell globbing expanding the same file into both options.","solutions":["Remove the duplicated path from one of the two lists: pass the path either via --take-remote or --keep-local, never both.","If unsure which side to keep, run with --dry-run first to inspect the conflict, then re-run with a single resolution flag.","In scripts, deduplicate and de-mutex the path sets before building the command line (e.g. skip a path already present in the other list)."],"exampleFix":"# before\nmise bootstrap dotfiles pull --take-remote ~/.zshrc --keep-local ~/.zshrc\n# after\nmise bootstrap dotfiles pull --take-remote ~/.zshrc","handlingStrategy":"validation","validationCode":"const take = new Set(args.takeRemote);\nconst keep = new Set(args.keepLocal);\nconst dup = [...take].filter(p => keep.has(p));\nif (dup.length) throw new Error(`path in both --take-remote and --keep-local: ${dup.join(', ')}`);","typeGuard":"const isDisjoint = (a, b) => a.every(p => !b.includes(p));","tryCatchPattern":null,"preventionTips":["Build the two flag lists from disjoint sources in scripts and assert disjointness before invoking.","Run with --dry-run first to confirm intended resolutions.","Deduplicate paths (normalize ~ and symlinks) before passing them."],"tags":["cli","conflict-resolution","sync","mutually-exclusive-flags"],"backgroundTag":"mutually-exclusive-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"}