gitbutlerapp/gitbutler · info
validated pick arity above
Error message
validated pick arity above
What it means
Panic from `expect("validated pick arity above")` in the interactive-integration parser (but-workspace integrate_branch_upstream/parsing.rs:53). The match arm first bails unless `arguments.len() == 1`, then takes `arguments.first()`; with exactly one element the `first()` cannot be None. It is an unreachable-by-construction assertion tying the unwrap to the arity check directly above it.
Source
Thrown at crates/but-workspace/src/branch/integrate_branch_upstream/parsing.rs:53
.with_context(|| format!("line {line_number}: invalid message clause"))?;
let tokens = command_part.split_whitespace().collect::<Vec<_>>();
let Some(command) = tokens.first().copied() else {
continue;
};
let arguments = tokens.get(1..).unwrap_or_default();
let step = match command {
"pick" => {
if message_part.is_some() {
bail!("line {line_number}: pick does not accept a message clause");
}
if arguments.len() != 1 {
bail!("line {line_number}: pick requires exactly one commit");
}
let commit = arguments
.first()
.copied()
.expect("validated pick arity above");
InteractiveIntegrationStep::Pick {
commit_id: resolve_commit(commit, &allowed_commits).map_err(|err| {
anyhow::anyhow!("line {line_number}: invalid pick commit: {err}")
})?,
}
}
"merge" => {
if message_part.is_some() {
bail!("line {line_number}: merge does not accept a message clause");
}
if arguments.len() != 1 {
bail!("line {line_number}: merge requires exactly one commit");
}
let commit = arguments
.first()
.copied()
.expect("validated merge arity above");
InteractiveIntegrationStep::Merge {View on GitHub (pinned to caf1f223d3)
Solutions
- No caller-side action; valid inputs are enforced by the bails above
- If editing the parser, derive the value from the length check itself (e.g. `let [commit] = arguments.as_slice() else { bail!(...) };`) so validation and extraction cannot diverge
- Run the parser's fuzz/unit tests after touching arity rules
Example fix
// before
if arguments.len() != 1 { bail!("line {line_number}: pick requires exactly one commit"); }
let commit = arguments.first().copied().expect("validated pick arity above");
// after: single source of truth
let Some(commit) = arguments.first().copied() else {
bail!("line {line_number}: pick requires exactly one commit");
}; Defensive patterns
Strategy: validation
Validate before calling
// Validate the todo line shape before invoking integration if you generate it:
fn valid_pick_line(args: &[&str]) -> bool { args.len() == 1 } Prevention
- No user input reaches this expect; arity errors are reported by the bail! above
- Maintainers: prefer let-else/slice patterns so validation and extraction share one statement
When it happens
Trigger: Parsing an `integrate-branch-upstream` todo line `pick <commit>`; the panic could only fire if the preceding arity check were removed or made inconsistent (e.g. allowing 0 arguments) — no input reaches it in the shipped code.
Common situations: Maintainers extending the todo grammar (new optional argument forms); forks that relax arity validation; none for end users.
Related errors
- validated merge arity above
- anchor is always present in the order at this point
- checked all selectors are present
- validated non-empty squash commit list
- key was just inserted
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/6283e771f8f87b2c.
Report an issue: GitHub.