gitbutlerapp/gitbutler · error · anyhow::Error

The model returned more than one resolution for "{}"

Error message

The model returned more than one resolution for "{}"

What it means

validate_ai_response() allows at most one resolution object per conflicted file; a second entry for a path already seen (its resolved_files slot is filled) fails validation. Duplicate answers for one file are ambiguous, so the whole response is discarded and the model call is retried once.

Source

Thrown at crates/but-api/src/resolve/mod.rs:625

/// full-coverage picks plus the per-file display payload. Any mismatch fails
/// validation so the caller can retry the model once before giving up.
fn validate_ai_response(
    request: &ResolutionRequest,
    response: &ResolutionResponse,
) -> anyhow::Result<(apply::PicksPerFile, Vec<ResolvedFile>)> {
    let files_by_path = apply::index_files_by_path(request)?;
    let mut picks: apply::PicksPerFile = vec![BTreeMap::new(); request.files.len()];
    let mut resolved_files: Vec<Option<ResolvedFile>> = vec![None; request.files.len()];

    for resolution in &response.resolutions {
        let Some(&index) = files_by_path.get(&apply::normalize_path(&resolution.path)) else {
            bail!(
                "The model returned a resolution for \"{}\", which was not requested",
                resolution.path
            );
        };
        if resolved_files[index].is_some() {
            bail!(
                "The model returned more than one resolution for \"{}\"",
                resolution.path
            );
        }
        let file = &request.files[index];
        if resolution.hunks.len() != file.hunks.len() {
            bail!(
                "The model returned {} resolved hunks for \"{}\" but the file has {} conflicts",
                resolution.hunks.len(),
                file.path,
                file.hunks.len()
            );
        }
        if resolution.reasoning.trim().is_empty() {
            bail!("The model returned no reasoning for \"{}\"", file.path);
        }
        for (hunk_index, hunk) in resolution.hunks.iter().enumerate() {
            apply::ensure_no_markers(&hunk.resolved_content, &file.path)?;

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Rely on the built-in single retry, which re-prompts with the same request
  2. Use a stronger model or a stricter structured-output configuration if duplicates recur
  3. Fall back to per-hunk resolution (resolve_commit_conflict_hunks) which validates caller-supplied specs deterministically
Defensive patterns

Strategy: retry

Try / catch

try {
  await api.resolveCommitConflictsAi(commitId);
} catch (err) {
  if (String(err).includes('more than one resolution')) {
    await api.resolveCommitConflictsAi(commitId); // internal retry already spent; one more attempt
  } else throw err;
}

Prevention

When it happens

Trigger: The model splits one file into two resolution objects (e.g. one per conflict, or 'part 1/part 2'), or repeats the file in both a batch and a summary section of the structured output.

Common situations: Structured-output schemas with loose array constraints; models that emit per-hunk objects instead of per-file; long contexts where the model loses track and re-answers an earlier file.

Related errors


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