gitbutlerapp/gitbutler · error · anyhow::Error
The model returned {} resolved hunks for "{}" but the file h
Error message
The model returned {} resolved hunks for "{}" but the file has {} conflicts What it means
For each resolved file the model must return exactly one resolved hunk per conflict in that file - full coverage per file, not a subset. A count mismatch (merged two conflicts into one entry, skipped one, or invented extra) fails validation; the message reports both counts so the drift is visible. The call is retried once automatically.
Source
Thrown at crates/but-api/src/resolve/mod.rs:632
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)?;
picks[index].insert(
hunk_index,
apply::HunkPick::Content(hunk.resolved_content.clone()),
);
}
resolved_files[index] = Some(ResolvedFile {
path: file.path.clone(),View on GitHub (pinned to caf1f223d3)
Solutions
- Trust the automatic retry - a fresh sample often lands the correct count
- Move to a stronger model for files with many conflicts
- If it persists, resolve that file with explicit per-hunk specs (ours/theirs/content) via resolve_commit_conflict_hunks
Defensive patterns
Strategy: retry
Try / catch
try {
await api.resolveCommitConflictsAi(commitId);
} catch (err) {
const m = String(err).match(/returned (\d+) resolved hunks .* but the file has (\d+)/);
if (m) {
await api.resolveCommitConflictsAi(commitId); // count drift - resample once
} else throw err;
} Prevention
- For files with many conflicts, consider pre-splitting the work via per-hunk specs instead of whole-commit AI resolve
- Watch output-token limits: truncation-adjacent count drift is a capacity smell
- Keep the message counts handy for logging - they tell you which file drifts
When it happens
Trigger: Model collapses adjacent conflicts into a single resolution object, omits the 'easy' conflict, or emits hunks per a different mental model of the file. Anything other than resolution.hunks.len() == file.hunks.len() bails.
Common situations: Files with many conflicts where the model loses count; nested/adjacent marker blocks confusing the split; models that resolve the file wholesale in one hunk.
Related errors
- The model returned a resolution for "{}", which was not requ
- The model returned more than one resolution for "{}"
- The model returned no reasoning for "{}"
- The model returned no resolution for the conflicted file "{}
- The conflict in "{}" cannot be resolved automatically: {} Re
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/589cda660eab9081.
Report an issue: GitHub.