gitbutlerapp/gitbutler · info

validated merge arity above

Error message

validated merge arity above

What it means

Panic from `expect("validated merge arity above")` for the `merge` command in the same interactive-integration parser (parsing.rs:70). Identical pattern to `pick`: the arm bails unless `arguments.len() == 1` and then unwraps `first()`, so the expect is unreachable in the shipped code and exists only to document the dependency on the check above.

Source

Thrown at crates/but-workspace/src/branch/integrate_branch_upstream/parsing.rs:70

                    .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 {
                    commit_id: resolve_commit(commit, &allowed_commits).map_err(|err| {
                        anyhow::anyhow!("line {line_number}: invalid merge commit: {err}")
                    })?,
                }
            }
            "squash" => {
                if arguments.len() < 2 {
                    bail!("line {line_number}: squash requires at least two commits");
                }
                let commits = arguments
                    .iter()
                    .map(|commit| {
                        resolve_commit(commit, &allowed_commits).map_err(|err| {
                            anyhow::anyhow!(
                                "line {line_number}: invalid squash commit '{commit}': {err}"
                            )
                        })

View on GitHub (pinned to caf1f223d3)

Solutions

  1. No caller-side action
  2. When modifying the grammar, use slice-pattern extraction so the check and the unwrap are one statement
  3. Keep fuzz coverage (`cargo fuzz` or table-driven tests) over the todo grammar

Example fix

// before
if arguments.len() != 1 { bail!("line {line_number}: merge requires exactly one commit"); }
let commit = arguments.first().copied().expect("validated merge arity above");

// after
let [commit] = arguments.as_slice() else {
    bail!("line {line_number}: merge requires exactly one commit");
};
Defensive patterns

Strategy: validation

Validate before calling

fn valid_merge_line(args: &[&str]) -> bool { args.len() == 1 }

Prevention

When it happens

Trigger: Parsing a `merge <commit>` todo line; reachable only if the arity validation above is edited to allow zero arguments or the extraction is changed independently.

Common situations: Parser maintenance (adding optional message clauses to merge); forks altering arity rules; none for end users.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20). Data as JSON: /api/errors/9126f637f271c900. Report an issue: GitHub.