gitbutlerapp/gitbutler · error
FuzzyPickerItem::columns must return a searchable column
Error message
FuzzyPickerItem::columns must return a searchable column
What it means
filter_items in the TUI fuzzy picker calls FuzzyPickerItem::columns(SearchableToken(())) and requires that at least one returned column has a searchable token. If an item implementation returns no column marked searchable, `.find(...)` yields None and the `.expect(...)` panics. This is an internal contract between the FuzzyPickerItem trait and the picker's filtering logic: every item must expose at least one searchable column so the matcher can score it.
Solutions
- Open the FuzzyPickerItem implementation for the displayed item type and ensure at least one column returned has `searchable: Some(...)`
- Change the code to fall back gracefully instead of panicking: use `.find(...).ok()?` / `filter_map` to skip non-searchable items
- Add a debug_assert or unit test per item type asserting columns() yields a searchable column
Example fix
// before
let col = item
.columns(SearchableToken(()))
.into_iter()
.find(|col| col.searchable.is_some())
.expect("FuzzyPickerItem::columns must return a searchable column");
// after
let col = item
.columns(SearchableToken(()))
.into_iter()
.find(|col| col.searchable.is_some())?; Defensive patterns
Strategy: type-guard
Validate before calling
// Rust: verify an item is searchable before adding it to the picker
fn assert_searchable(item: &dyn FuzzyPickerItem) {
debug_assert!(
item.columns(SearchableToken(())).iter().any(|c| c.searchable.is_some()),
"FuzzyPickerItem must return at least one searchable column"
);
} Type guard
fn has_searchable_column(item: &dyn FuzzyPickerItem) -> bool {
item.columns(SearchableToken(())).iter().any(|c| c.searchable.is_some())
} Try / catch
// Prefer skipping unfilterable items over panicking:
let col = match item.columns(SearchableToken(())).into_iter().find(|c| c.searchable.is_some()) {
Some(c) => c,
None => return None, // in filter_map
}; Prevention
- Add a unit test per FuzzyPickerItem implementation asserting a searchable column exists
- Make the searchable column the first element by convention and review new columns() impls
- Use debug_assert in the trait contract docs so CI debug builds catch violations early
When it happens
Trigger: Pressing a key that triggers fuzzy filtering in the `but` status TUI while any item in the picker violates the trait contract — i.e. its `columns()` implementation returns no column with `searchable: Some(_)`.
Common situations: Adding a new FuzzyPickerItem variant (or modifying columns()) and forgetting to tag at least one column as searchable; a refactor changes column construction so `searchable` becomes None; a column list becomes empty for a particular data state.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- a committed transaction always materializes a workspace
- anchor is always present in the order at this point
- AtSegment anchor always has oldest commit resolved
- broker already configured
- broker has not been configured
AI-assisted analysis of gitbutlerapp/gitbutler@58e5313667 (2026-09-18).
Data as JSON: /api/errors/c935a3d2dec9ae48.
Report an issue: GitHub.
Appendix: source
Thrown at crates/but/src/command/legacy/status/tui/fuzzy_picker.rs:271
if query.is_empty() {
self.items_to_show.extend(
self.items
.iter()
.enumerate()
.map(|(item_idx, _)| ItemToShow::Plain { item_idx }),
);
} else {
let mut fuzzy_matches = self
.items
.iter()
.enumerate()
.filter_map(|(item_idx, item)| {
let col = item
.columns(SearchableToken(()))
.into_iter()
.find(|col| col.searchable.is_some())
.expect("FuzzyPickerItem::columns must return a searchable column");
let (score, indices) = self.matcher.fuzzy_indices(&col.text, query)?;
Some((item_idx, col, score, indices))
})
.collect::<Vec<_>>();
fuzzy_matches.sort_unstable_by(|(_, _, score_a, _), (_, _, score_b, _)| {
score_a.cmp(score_b).reverse()
});
self.items_to_show.extend(fuzzy_matches.into_iter().map(
|(item_idx, _, _, indices)| ItemToShow::FuzzyMatch {
item_idx,
char_indices: indices,
},
));
}
}
pub fn handle_message(
mut self,View on GitHub (pinned to 58e5313667)