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
- 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).
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
- 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.
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
- {} is not a conflict
- {flag} cannot be used with a bootstrap subcommand
- cannot synchronize: {reason}
- partial pulls are not supported: apply the complete setup wi
- save {} before choosing --keep-local
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/af2a777318023f56.
Report an issue: GitHub.