gitbutlerapp/gitbutler · error
non-empty conflicts map contains a commit
Error message
non-empty conflicts map contains a commit
What it means
Invariant in the 'but resolve' output path: the code runs inside a block that only executes when at least one conflict was recorded for a branch, and it then takes the first commit of that branch's resolution queue to suggest the next 'but resolve <id>'. The expect fires if the per-branch queue is empty while the aggregate conflicts map is not - an internal desync between the two structures.
Source
Thrown at crates/but/src/command/legacy/resolve.rs:1284
" {} {}",
t.important.paint("Branch:"),
t.local_branch.paint(branch_name)
)?;
for commit in commits {
writeln!(
human_out,
" {} {} {}",
t.sym().dot.error(),
t.hint.paint(&commit.commit_short_id),
commit.commit_message
)?;
}
}
let next_commit = resolution_queue
.first()
.copied()
.expect("non-empty conflicts map contains a commit");
writeln!(
human_out,
"Resolve the next commit with {}.",
t.command_suggestion
.paint(format!("but resolve {}", next_commit.commit_short_id))
)?;
}
}
if let Some(json_out) = out.for_json() {
let conflicts_by_branch = conflicts_after
.iter()
.map(|(branch_name, commits)| {
(
branch_name,
commits
.iter()
.map(|commit| {View on GitHub (pinned to 2497b8007a)
Solutions
- Re-run 'but resolve' (or its listing subcommand) to refresh conflict state from the workspace
- Report the scenario - queue/map desync is an internal bug, not a user error
- Maintainer: derive next_commit from the same iteration that printed the branch header instead of a second lookup
Example fix
// before
let next_commit = resolution_queue.first().copied()
.expect("non-empty conflicts map contains a commit");
// after
let Some(next_commit) = resolution_queue.first().copied() else {
tracing::warn!(branch = %branch_name, "conflicts recorded but resolution queue empty");
continue;
}; Defensive patterns
Strategy: validation
Validate before calling
// Keep the conflicts map and resolution queue in one structure so they cannot desync
struct BranchConflicts {
branch: BranchName,
queue: NonEmpty<ConflictedCommit>, // empty-by-construction is impossible
} Prevention
- Derive the suggested next commit from the same iteration that renders each branch block
- Re-list conflicts before printing suggestions after any workspace mutation
- Use NonEmpty containers for queues that accompany non-empty conflict maps
When it happens
Trigger: Conflicts are recorded under a branch key whose resolution queue ended up empty after earlier steps consumed or filtered it; a refactor moves queue population so the map and queue are no longer filled together.
Common situations: Long-running resolve sessions resuming from persisted state; workspace updates landing between listing conflicts and printing suggestions.
Related errors
- target OID must exist when ahead calculation is enabled
- target OID must exist when merge check is enabled
- object for prefix exists
- WithSyntaxHighlighting ensures the line is highlighted
- classified branches are guaranteed to be non-empty
AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17).
Data as JSON: /api/errors/152bbf5b36406a44.
Report an issue: GitHub.