gitbutlerapp/gitbutler · error · anyhow::Error
"{}" has {} conflict{}, but conflict {} was addressed
Error message
"{}" has {} conflict{}, but conflict {} was addressed What it means
locate_hunk() resolves each spec's (path, 1-based hunk) address against the request. Hunks are numbered starting at 1, so hunk 0 is always invalid, and a number larger than the file's conflict count is stale. The message tells you the file's real hunk count so you can recompute. Nothing is written when this fails.
Source
Thrown at crates/but-api/src/resolve/apply.rs:120
// Naming the reason matters here: the file *is* conflicted, it just
// has no hunks to address, so "not a conflicted file" would read as
// a caller mistake rather than a property of the conflict.
let normalized = normalize_path(path);
match request
.manual
.iter()
.find(|file| normalize_path(&file.path) == normalized)
{
Some(file) => format!(
"\"{path}\" cannot be resolved this way: {} Resolve this commit in edit mode instead.",
file.reason
),
None => format!("\"{path}\" is not a conflicted file of this commit"),
}
})?;
let file = &request.files[file_index];
if hunk == 0 || hunk > file.hunks.len() {
bail!(
"\"{}\" has {} conflict{}, but conflict {} was addressed",
file.path,
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)View on GitHub (pinned to caf1f223d3)
Solutions
- Re-fetch the conflict state with commit_conflicts(commit_id) and recompute spec hunk numbers from its fresh hunks list
- After any partial resolution, address follow-up specs to the new_commit id returned by that call
- Treat hunk indices as 1-based positions in the file's hunk list
Example fix
// before: reusing stale hunk numbers after a partial resolve await api.resolveCommitConflictHunks(commitId, specs); // after: re-sync against the current commit first const conflicts = await api.commitConflicts(commitId); const file = conflicts.files.find(f => normalizePath(f.path) === normalizePath(spec.path)); const safeSpecs = file ? specs.filter(s => s.path === file.path && s.hunk >= 1 && s.hunk <= file.hunks.length) : []; await api.resolveCommitConflictHunks(commitId, safeSpecs);
Defensive patterns
Strategy: validation
Validate before calling
// Recompute against the live conflict list before resolving
const conflicts = await api.commitConflicts(commitId);
const file = conflicts.files.find(f => normalizePath(f.path) === normalizePath(spec.path));
const ok = file !== undefined && spec.hunk >= 1 && spec.hunk <= file.hunks.length;
if (!ok) throw new Error(`stale hunk ${spec.hunk} for ${spec.path}; refresh conflicts`); Try / catch
try {
await api.resolveCommitConflictHunks(commitId, specs);
} catch (err) {
if (/but conflict \d+ was addressed/.test(String(err))) {
const fresh = await api.commitConflicts(commitId);
specs = remapSpecsToFreshHunks(specs, fresh); // rebuild indices, then retry once
await api.resolveCommitConflictHunks(commitId, specs);
} else throw err;
} Prevention
- Treat hunk indices as 1-based positions in commit_conflicts().files[i].hunks
- After every resolve, adopt the returned new_commit as the id for subsequent operations
- Disable batch apply while a resolve is in flight so two callers cannot invalidate each other's indices
When it happens
Trigger: Calling resolve_commit_conflict_hunks with hunk numbers computed from a DIFFERENT view of the commit: a previous partial resolution rewrote the commit (new id, fewer hunks), the UI held an old conflict list, or the caller passed 0-based indices from some other diff/hunk API.
Common situations: Stale UI state after a partial resolve (must re-fetch against the returned new_commit); two concurrent resolutions racing; mixing 0-based indices from a git-diff style API with this 1-based API.
Related errors
- Conflict {} of "{}" was addressed more than once
- The resolution for "{path}" contains a conflict marker ({mar
- Validation
- Re-merging the conflicting trees of commit {commit_id} yield
- Commit {commit_id} has no conflicted files to resolve
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/2f9a5c05240e3948.
Report an issue: GitHub.