gitbutlerapp/gitbutler · error
source branches is already checked to be non-empty
Error message
source branches is already checked to be non-empty
What it means
Invariant at the end of squash source resolution: the loop pushes one source_branches entry per iteration, and the loop only runs over inputs already validated to contain at least one source branch, so the final NonEmpty::from_vec cannot fail. A panic means earlier non-empty validation was bypassed - for example a parser or refactor change let an empty sources list reach this code.
Source
Thrown at crates/but/src/command/legacy/squash.rs:919
true
}
});
commits_on_branch_sources.append(&mut commits_on_branch);
if !target_commit_exists_on_branch {
branches_to_remove.push(source_branch_name.clone());
}
}
BranchSquashTarget::Uncommitted => {
branches_to_remove.push(source_branch_name.clone());
commits_on_branch_sources.append(&mut commits_on_branch);
}
}
source_branches.push(source_branch_name);
}
let source_branches = NonEmpty::from_vec(source_branches)
.expect("source branches is already checked to be non-empty");
Ok(ResolvedSquash::Branches {
target,
source_commits: commits_on_branch_sources,
source_branches,
branches_to_remove,
})
}
fn resolve_reword(
message: Option<Vec<String>>,
no_message: bool,
use_target_message: bool,
use_source_message: bool,
) -> CliResult<HowToRewordTarget> {
if use_target_message {
Ok(HowToRewordTarget::UseTargetMessage)
} else if use_source_message {View on GitHub (pinned to 2497b8007a)
Solutions
- Verify the command was invoked with at least one source (branch/commit) - empty sources should be rejected at parse time
- Report the invocation; maintainers should keep the early non-empty check adjacent to parsing
- Convert the expect into an internal-error result for diagnosability
Example fix
// before
let source_branches = NonEmpty::from_vec(source_branches)
.expect("source branches is already checked to be non-empty");
// after
let source_branches = NonEmpty::from_vec(source_branches)
.ok_or_else(|| anyhow::anyhow!("internal: squash sources validated non-empty but resolved empty"))?; Defensive patterns
Strategy: validation
Validate before calling
// Reject empty sources at parse time, adjacent to the same function
let source_branches = NonEmpty::from_vec(source_branches).ok_or_else(|| {
bad_input("squash needs at least one source branch").arg_name("<SOURCES>")
})?; Prevention
- Validate non-empty sources once at the CLI boundary and keep the check next to the re-wrap
- When refactoring squash parsing, re-run the squash CLI tests covering single and multiple sources
- Prefer ok_or_else with a user-facing message over expect for this pattern
When it happens
Trigger: A refactor removes or weakens the earlier 'at least one source' validation; a code path returns from the loop without pushing yet still reaches the re-wrap; a new squash mode processes zero sources.
Common situations: Refactors of squash argument parsing and validation; empty --source lists that used to be rejected earlier in the flow.
Related errors
- deduping a NonEmpty will never make it empty
- classified branches are guaranteed to be non-empty
- committed files being non-empty means paths are non-empty
- changes being non-empty means paths are non-empty
- target OID must exist when ahead calculation is enabled
AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17).
Data as JSON: /api/errors/b395cf7d7ef53534.
Report an issue: GitHub.