gitbutlerapp/gitbutler · error

no searchable columns

Error message

no searchable columns

What it means

The TUI fuzzy picker enforces a trait contract: FuzzyPickerItem::columns(SearchableToken(())) must return at least one Col with searchable == Some. During layout the picker inspects only the first item (self.items[0]) to locate the searchable column index and panics if none of its columns is searchable. Because it also indexes items[0], an empty items list panics with index-out-of-bounds just before this expect.

Source

Thrown at crates/but/src/command/legacy/status/tui/fuzzy_picker.rs:118

        let input_height: u16 = 1;

        let col_widths = self
            .items
            .iter()
            .map(|item| item.columns(SearchableToken(())))
            .map(|cols| {
                cols.into_iter()
                    .map(|col| col.text.width())
                    .collect::<Vec<_>>()
            })
            .collect::<Vec<_>>();

        // assume the searchable column is at the same index on every row
        let searchable_col_idx = self.items[0]
            .columns(SearchableToken(()))
            .into_iter()
            .position(|col| col.searchable.is_some())
            .expect("no searchable columns");

        // assume each row contains the same number of columns
        let num_cols = col_widths[0].len();

        let column_spacing = 2;

        let mut col_constraints = (0..num_cols)
            .map(|n| col_widths.iter().map(|c| &c[n]).collect::<Vec<_>>())
            .map(|col| col.iter().copied().max().unwrap())
            .map(|&width| Constraint::Length(width as u16))
            .collect::<Vec<_>>();
        for (i, constraint) in col_constraints.iter_mut().enumerate() {
            if i == searchable_col_idx {
                *constraint = Constraint::Min(1);
                break;
            }
        }

View on GitHub (pinned to 2497b8007a)

Solutions

  1. In the FuzzyPickerItem::columns impl, set searchable: Some(searchable) on exactly one Col (copy the pattern from fuzzy_picker.rs sibling copy_selection_picker.rs:236-240)
  2. Guard the caller: don't open the picker when items.is_empty() — show a 'nothing to pick' message instead
  3. Replace the expect with a fallback (search column 0) or skip rendering, so contract violations surface as wrong UI instead of a crash
  4. Add a unit test that builds the picker for each item type and asserts a searchable column exists

Example fix

// before — new item impl, nothing searchable → panic at layout
fn columns(&self, _searchable: SearchableToken) -> impl IntoIterator<Item = Col<'_>> {
    [Col { text: self.name.clone(), searchable: None }]
}

// after — mark the column users fuzzy-search on
fn columns(&self, searchable: SearchableToken) -> impl IntoIterator<Item = Col<'_>> {
    [Col { text: self.name.clone(), searchable: Some(searchable) }]
}
Defensive patterns

Strategy: validation

Validate before calling

// before constructing/opening the picker
fn picker_items_valid(items: &[impl FuzzyPickerItem]) -> bool {
    !items.is_empty()
        && items.iter().all(|i| i.columns(SearchableToken(())).into_iter().any(|c| c.searchable.is_some()))
}
if !picker_items_valid(&items) { /* show 'nothing to pick' instead of opening the picker */ }

Type guard

fn has_searchable_column(item: &impl FuzzyPickerItem) -> bool {
    item.columns(SearchableToken(()))
        .into_iter()
        .any(|col| col.searchable.is_some())
}

Prevention

When it happens

Trigger: Opening any fuzzy picker in the TUI (copy-selection picker, stack picker) where the item type's columns impl returns every Col with searchable: None, or drops the SearchableToken parameter instead of attaching it to exactly one column; also constructing a picker with an empty items vec (empty workspace/stack).

Common situations: Implementing FuzzyPickerItem for a new TUI list type and forgetting to mark the searchable column (reference impls: copy_selection_picker.rs:236, app/mod.rs:2066 set searchable: Some on the searched column); conditional impls that only sometimes mark a column searchable; empty result lists passed to the picker.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17). Data as JSON: /api/errors/15e71be450e6bb37. Report an issue: GitHub.