gitbutlerapp/gitbutler · error · anyhow::Error

Two conflicted paths normalize to the same value ({:?}); res

Error message

Two conflicted paths normalize to the same value ({:?}); resolve this commit manually instead

What it means

index_files_by_path() keys every conflicted file of the commit by its normalized path (trim, backslashes to slashes, strip leading ./, collapse duplicate slashes). If two distinct conflicted paths normalize to the same key, a path-addressed spec would be ambiguous between two files, so the whole request is rejected with advice to resolve manually. This is a property of the commit itself, not of the specs - every resolve call on such a commit fails.

Source

Thrown at crates/but-api/src/resolve/apply.rs:141

            file.hunks.len(),
            if file.hunks.len() == 1 { "" } else { "s" },
            hunk
        );
    }
    Ok((file_index, hunk - 1))
}

/// Map normalized request paths to file indices, rejecting collisions.
pub(crate) fn index_files_by_path(
    request: &ResolutionRequest,
) -> anyhow::Result<BTreeMap<String, usize>> {
    let mut files_by_path = BTreeMap::new();
    for (index, file) in request.files.iter().enumerate() {
        if files_by_path
            .insert(normalize_path(&file.path), index)
            .is_some()
        {
            bail!(
                "Two conflicted paths normalize to the same value ({:?}); resolve this commit manually instead",
                normalize_path(&file.path)
            );
        }
    }
    Ok(files_by_path)
}

/// Reject content that contains a conflict-marker-shaped line.
pub(crate) fn ensure_no_markers(content: &str, path: &str) -> anyhow::Result<()> {
    if let Some(marker) = content
        .lines()
        .map(|line| line.strip_suffix('\r').unwrap_or(line))
        .find(|line| is_marker_shaped(line))
    {
        bail!("The resolution for \"{path}\" contains a conflict marker ({marker:?})");
    }
    Ok(())

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Resolve this particular commit manually, as the message says (edit mode or git mergetool outside the API)
  2. Check the commit's conflicted paths for separator-only or './'-only differences and normalize them in the merge
  3. If reproducible, report it - it is a defensive guard against ambiguous path addressing, and the input commit shape is worth a bug report
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await api.resolveCommitConflictHunks(commitId, specs);
} catch (err) {
  if (String(err).includes('normalize to the same value')) {
    // commit-level ambiguity: no spec shape can fix it
    routeToManualResolution(commitId);
  } else throw err;
}

Prevention

When it happens

Trigger: A conflicted commit containing two paths that differ only in separator style or redundant components - e.g. 'dir/file' and '.\\dir\\file', or 'a//b' and 'a/b' - which can appear after rename/rename conflicts on case-insensitive filesystems or unusual merge tooling. Any resolve_commit_conflict_hunks / AI resolve call on that commit then bails during validation.

Common situations: Case-renames on macOS/Windows producing both spellings; merge commits created by external tools that mixed path separators; repos with paths that only differ pre-normalization.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20). Data as JSON: /api/errors/7d18c93483827c4c. Report an issue: GitHub.