gitbutlerapp/gitbutler · info
validated non-empty squash commit list
Error message
validated non-empty squash commit list
What it means
Panic from `expect("validated non-empty squash commit list")` on `ordered_commit_ids.first()` in squash-step planning (plan.rs:285). The function bails at the top when `commit_ids.len() < 2`, and `ordered_commit_ids` is either the mapped selectors (same count) or `commit_ids.to_vec()`, so it has at least two elements and `first()` always yields the squash target. Unreachable by construction.
Source
Thrown at crates/but-workspace/src/branch/integrate_branch_upstream/plan.rs:285
.into_iter()
.map(|selector| selector.expect("checked all selectors are present"))
.collect::<Vec<_>>(),
)?;
ordered_selectors
.iter()
.map(|selector| {
editor
.find_selectable_commit(*selector)
.map(|(_, commit)| commit.id)
})
.collect::<Result<Vec<_>>>()?
} else {
commit_ids.to_vec()
};
let target_commit_id = *ordered_commit_ids
.first()
.expect("validated non-empty squash commit list");
let merge_subject_ids = commit_ids
.iter()
.copied()
.filter(|commit_id| *commit_id != target_commit_id)
.collect::<Vec<_>>();
let merge_outcome = editor.merge_commit_changes_to_tree(
target_commit_id,
merge_subject_ids,
editor.repo().merge_options_force_ours()?,
)?;
let squashed_parent = editor
.repo()
.merge_base_octopus(ordered_commit_ids.iter().copied())
.context("failed to compute squash merge-base")?
.detach();
let tip_commit_id = *ordered_commit_ids
.last()View on GitHub (pinned to caf1f223d3)
Solutions
- No caller-side action — the `len() < 2` bail above guarantees non-emptiness
- If editing, use `let Some(target) = ordered_commit_ids.first() else { bail!("squash produced no commits") };` so future edits cannot turn a logic slip into a panic
- Keep a unit test for the single-commit rejection path
Example fix
// before
let target_commit_id = *ordered_commit_ids.first().expect("validated non-empty squash commit list");
// after
let Some(target_commit_id) = ordered_commit_ids.first() else {
bail!("squash step must have at least two commits");
}; Defensive patterns
Strategy: validation
Validate before calling
// Reject squash plans with fewer than two commits before planning:
fn valid_squash_step(commit_ids: &[ObjectId]) -> bool { commit_ids.len() >= 2 } Prevention
- Plan validation already rejects len < 2 with a clear error
- Maintainers: replace expect with let-else + bail when editing this function
When it happens
Trigger: Building a squash step from an interactive-integration plan; could only fire if the length guard is removed or `ordered_commit_ids` gains a filtering step that can empty it.
Common situations: Maintainers editing squash planning (e.g. dropping already-applied commits from the ordered list); none for end users.
Related errors
- checked all selectors are present
- anchor is always present in the order at this point
- AtSegment anchor always has oldest commit resolved
- a committed transaction always materializes a workspace
- if it was found before it will be found as id
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/040bf2a14ba37711.
Report an issue: GitHub.