{"record":{"id":"6ff45b6fe764ab24","repo":"gitbutlerapp/gitbutler","slug":"the-model-returned-more-than-one-resolution-for","errorCode":null,"errorMessage":"The model returned more than one resolution for \"{}\"","messagePattern":"The model returned more than one resolution for \"(.+?)\"","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/but-api/src/resolve/mod.rs","lineNumber":625,"sourceCode":"/// full-coverage picks plus the per-file display payload. Any mismatch fails\n/// validation so the caller can retry the model once before giving up.\nfn validate_ai_response(\n    request: &ResolutionRequest,\n    response: &ResolutionResponse,\n) -> anyhow::Result<(apply::PicksPerFile, Vec<ResolvedFile>)> {\n    let files_by_path = apply::index_files_by_path(request)?;\n    let mut picks: apply::PicksPerFile = vec![BTreeMap::new(); request.files.len()];\n    let mut resolved_files: Vec<Option<ResolvedFile>> = vec![None; request.files.len()];\n\n    for resolution in &response.resolutions {\n        let Some(&index) = files_by_path.get(&apply::normalize_path(&resolution.path)) else {\n            bail!(\n                \"The model returned a resolution for \\\"{}\\\", which was not requested\",\n                resolution.path\n            );\n        };\n        if resolved_files[index].is_some() {\n            bail!(\n                \"The model returned more than one resolution for \\\"{}\\\"\",\n                resolution.path\n            );\n        }\n        let file = &request.files[index];\n        if resolution.hunks.len() != file.hunks.len() {\n            bail!(\n                \"The model returned {} resolved hunks for \\\"{}\\\" but the file has {} conflicts\",\n                resolution.hunks.len(),\n                file.path,\n                file.hunks.len()\n            );\n        }\n        if resolution.reasoning.trim().is_empty() {\n            bail!(\"The model returned no reasoning for \\\"{}\\\"\", file.path);\n        }\n        for (hunk_index, hunk) in resolution.hunks.iter().enumerate() {\n            apply::ensure_no_markers(&hunk.resolved_content, &file.path)?;","sourceCodeStart":607,"sourceCodeEnd":643,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-api/src/resolve/mod.rs#L607-L643","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Rely on the built-in single retry, which re-prompts with the same request","Use a stronger model or a stricter structured-output configuration if duplicates recur","Fall back to per-hunk resolution (resolve_commit_conflict_hunks) which validates caller-supplied specs deterministically"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await api.resolveCommitConflictsAi(commitId);\n} catch (err) {\n  if (String(err).includes('more than one resolution')) {\n    await api.resolveCommitConflictsAi(commitId); // internal retry already spent; one more attempt\n  } else throw err;\n}","preventionTips":["If you inject the resolver yourself (resolve_commit_conflicts_with), dedupe response.resolutions by path before returning","Cap retries at one extra attempt - persistent duplicates indicate the model cannot follow the per-file schema","Report recurring duplicate responses alongside the provider/model pair"],"tags":["ai-resolution","llm-validation","duplicate","resolve-api"],"backgroundTag":"llm-response-validation-failed","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}