jdx/mise · error

choose only one resolution for {}

Error message

choose only one resolution for {}

What it means

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.

Source

Thrown at src/system/history/sync/apply.rs:148

        .iter()
        .map(|path| normalize_target(path))
        .collect();

    // Store choices without publishing or applying any part of the setup.
    let mut sync_state = state::load(repo)?;
    let shared = super::share::current(repo, tracked)?.objects();
    let encrypted = super::files::encrypted_paths(repo, status.upstream_commit.as_deref())?;
    for conflict in &status.conflicts {
        let Some(local) = roots
            .locate(&conflict.branch_path)
            .path()
            .map(Path::to_path_buf)
        else {
            continue;
        };
        if take_remote.contains(&local) || keep_local.contains(&local) {
            if take_remote.contains(&local) && keep_local.contains(&local) {
                bail!("choose only one resolution for {}", display_path(&local));
            }
            let live = live_object(repo, &local)?;
            let saved = shared.get(&conflict.branch_path).cloned();
            let saved_mode = permissions_at(
                repo,
                planned_head.as_deref(),
                &conflict.branch_path,
                saved.as_ref(),
            )?;
            if keep_local.contains(&local)
                && (live != saved || live_permissions(&local)? != saved_mode)
            {
                bail!("save {} before choosing --keep-local", display_path(&local));
            }
            let remote = match status.upstream_commit.as_deref() {
                Some(head) => repo
                    .object_at(head, &conflict.branch_path)?
                    .map(|object| {

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Remove the duplicated path from one of the two lists: pass the path either via --take-remote or --keep-local, never both.
  2. If unsure which side to keep, run with --dry-run first to inspect the conflict, then re-run with a single resolution flag.
  3. 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).

Example fix

# before
mise bootstrap dotfiles pull --take-remote ~/.zshrc --keep-local ~/.zshrc
# after
mise bootstrap dotfiles pull --take-remote ~/.zshrc
Defensive patterns

Strategy: validation

Validate before calling

const take = new Set(args.takeRemote);
const keep = new Set(args.keepLocal);
const dup = [...take].filter(p => keep.has(p));
if (dup.length) throw new Error(`path in both --take-remote and --keep-local: ${dup.join(', ')}`);

Type guard

const isDisjoint = (a, b) => a.every(p => !b.includes(p));

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/af2a777318023f56. Report an issue: GitHub.