Universal-Debloater-Alliance/universal-android-debloater-next-generation · error
pack-state must be selected
Error message
pack-state must be selected
What it means
filter_package_lists unwraps `self.selected_package_state` (Option<PackageState>) with `.expect("pack-state must be selected")` while building the active filter set, and likewise unwraps selected_user for indexing phone_packages. The function assumes all three dropdowns (list type, package state, removal, user) always hold a selection; a None in the package-state dropdown panics.
Solutions
- Initialize selected_package_state (and selected_user, selected_removal) with sensible defaults at view construction.
- Convert all the expects into early-return guards: `let (Some(list_filter), Some(package_filter), Some(removal_filter)) = (...) else { return };`
- Only invoke filter_package_lists after a 'filters ready' flag is set once all dropdowns are populated.
- Reset all four selections atomically together on device/view changes so they can never be partially None.
Example fix
// before
let package_filter: PackageState = self
.selected_package_state
.expect("pack-state must be selected");
// after
let Some(package_filter) = self.selected_package_state else { return }; Defensive patterns
Strategy: type-guard
Validate before calling
if self.selected_package_state.is_none() || self.selected_user.is_none() {
eprintln!("package-state/user not selected; skipping filter");
return;
} Type guard
fn can_filter(view: &ListView) -> bool {
view.selected_package_state.is_some() && view.selected_user.is_some()
} Try / catch
let (Some(package_filter), Some(user)) = (self.selected_package_state, self.selected_user.as_ref()) else { return }; Prevention
- Give every dropdown a concrete default value at initialization.
- When switching devices/views, clear or restore all filter Options atomically.
- Convert multi-expect filter setups into a single destructuring let-else guard.
When it happens
Trigger: Running the filter when selected_package_state is None: the package-state dropdown wasn't initialized yet (view constructed but defaults not applied), a device/view switch cleared selections, or a filter message arrives during teardown/reset while the user dropdown or state dropdown was already reset.
Common situations: Rapid device switching while the packages view is filtering; settings restore paths that set some dropdowns but not the package-state one; refactors that initialize dropdowns lazily instead of with defaults.
Related errors
- Device should be selected
- UAD-list type must be selected
- {e}
- There must be 1 tab after serial
- There must be at least 1 ':'-separated component
AI-assisted analysis of Universal-Debloater-Alliance/universal-android-debloater-next-generation@64465c850c (2026-09-12).
Data as JSON: /api/errors/23998b6f9f3493c0.
Report an issue: GitHub.
Appendix: source
Thrown at crates/uad-gui/src/views/list.rs:746
selected_pkgs_ctn,
modal_btn_row,
]
.spacing(10)
.align_x(Alignment::Center)
},
)
.width(900)
.height(Length::Shrink)
.max_height(700)
.style(style::Container::Background)
.into()
}
fn filter_package_lists(&mut self) {
let list_filter: UadList = self.selected_list.expect("UAD-list type must be selected");
let package_filter: PackageState = self
.selected_package_state
.expect("pack-state must be selected");
let removal_filter: Removal = self
.selected_removal
.expect("removal recommendation must be selected");
self.filtered_packages = self.phone_packages
[self.selected_user.expect("User must be selected").index]
.iter()
// we must filter the indices associated with pack-rows,
// that's why `enumerate` is before `filter`.
.enumerate()
.filter(|(_, p)| {
(list_filter == UadList::All || p.list == list_filter)
&& (package_filter == PackageState::All || p.state == package_filter)
&& (removal_filter == Removal::All || p.removal == removal_filter)
&& (self.input_value.is_empty()
|| matches_search(&p.name, &self.input_value, Some(&p.description)))
})
.map(|(i, _)| i)View on GitHub (pinned to 64465c850c)