gitbutlerapp/gitbutler · info

checked all selectors are present

Error message

checked all selectors are present

What it means

Panic from `expect("checked all selectors are present")` in squash-step planning (but-workspace integrate_branch_upstream/plan.rs:268). The code maps commit ids to `try_select_commit` options, takes the `all(Option::is_some)` branch, and then unwraps each selector inside `map`. Because the branch is guarded by the `all()` check, every `expect` is provably Some; the assertion just records that coupling.

Source

Thrown at crates/but-workspace/src/branch/integrate_branch_upstream/plan.rs:268

/// before later integration graph mutations can rewire step-graph ancestry.
fn prepare_squash_step_for_editor<M: RefMetadata>(
    editor: &Editor<'_, '_, M>,
    commit_ids: &[gix::ObjectId],
    message: Option<&str>,
) -> Result<gix::ObjectId> {
    if commit_ids.len() < 2 {
        bail!("Squash step must have at least two commits");
    }

    let maybe_selectors = commit_ids
        .iter()
        .map(|commit_id| editor.try_select_commit(*commit_id))
        .collect::<Vec<_>>();
    let ordered_commit_ids = if maybe_selectors.iter().all(Option::is_some) {
        let ordered_selectors = editor.order_commit_selectors_by_parentage(
            maybe_selectors
                .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

View on GitHub (pinned to caf1f223d3)

Solutions

  1. No caller-side action
  2. If refactoring, replace option-juggling with `collect::<Option<Vec<_>>>()` so absence propagates as None instead of relying on the paired expect
  3. Add a plan-level test with one unselectable commit to pin the fallback branch

Example fix

// before
let maybe_selectors = commit_ids.iter().map(|id| editor.try_select_commit(*id)).collect::<Vec<_>>();
let ordered_commit_ids = if maybe_selectors.iter().all(Option::is_some) {
    let ordered = editor.order_commit_selectors_by_parentage(
        maybe_selectors.into_iter().map(|s| s.expect("checked all selectors are present")).collect()
    )?;
    ...

// after
let maybe_selectors = commit_ids.iter().map(|id| editor.try_select_commit(*id)).collect::<Option<Vec<_>>>();
let ordered_commit_ids = if let Some(selectors) = maybe_selectors {
    let ordered = editor.order_commit_selectors_by_parentage(selectors)?;
    ...
Defensive patterns

Strategy: validation

Validate before calling

// If you pre-validate the plan, ensure every squash commit id is selectable:
let all_selectable = commit_ids.iter()
    .all(|id| editor.try_select_commit(*id).is_some());

Prevention

When it happens

Trigger: Planning a squash step whose commit ids are all selectable in the editor; the panic could only fire if the `all()` guard and the later unwrap are separated by an edit (e.g. filtering selectors in between) — not reachable in the shipped code.

Common situations: Maintainers refactoring plan.rs (e.g. partial-selector fallback handling); none for end users.

Related errors


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