{"record":{"id":"23998b6f9f3493c0","repo":"Universal-Debloater-Alliance/universal-android-debloater-next-generation","slug":"pack-state-must-be-selected","errorCode":null,"errorMessage":"pack-state must be selected","messagePattern":"pack-state must be selected","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/uad-gui/src/views/list.rs","lineNumber":746,"sourceCode":"                    selected_pkgs_ctn,\n                    modal_btn_row,\n                ]\n                .spacing(10)\n                .align_x(Alignment::Center)\n            },\n        )\n        .width(900)\n        .height(Length::Shrink)\n        .max_height(700)\n        .style(style::Container::Background)\n        .into()\n    }\n\n    fn filter_package_lists(&mut self) {\n        let list_filter: UadList = self.selected_list.expect(\"UAD-list type must be selected\");\n        let package_filter: PackageState = self\n            .selected_package_state\n            .expect(\"pack-state must be selected\");\n        let removal_filter: Removal = self\n            .selected_removal\n            .expect(\"removal recommendation must be selected\");\n\n        self.filtered_packages = self.phone_packages\n            [self.selected_user.expect(\"User must be selected\").index]\n            .iter()\n            // we must filter the indices associated with pack-rows,\n            // that's why `enumerate` is before `filter`.\n            .enumerate()\n            .filter(|(_, p)| {\n                (list_filter == UadList::All || p.list == list_filter)\n                    && (package_filter == PackageState::All || p.state == package_filter)\n                    && (removal_filter == Removal::All || p.removal == removal_filter)\n                    && (self.input_value.is_empty()\n                        || matches_search(&p.name, &self.input_value, Some(&p.description)))\n            })\n            .map(|(i, _)| i)","sourceCodeStart":728,"sourceCodeEnd":764,"githubUrl":"https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/blob/64465c850c7ed36329e67165ac08501abffb218e/crates/uad-gui/src/views/list.rs#L728-L764","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nlet package_filter: PackageState = self\n    .selected_package_state\n    .expect(\"pack-state must be selected\");\n// after\nlet Some(package_filter) = self.selected_package_state else { return };","handlingStrategy":"type-guard","validationCode":"if self.selected_package_state.is_none() || self.selected_user.is_none() {\n    eprintln!(\"package-state/user not selected; skipping filter\");\n    return;\n}","typeGuard":"fn can_filter(view: &ListView) -> bool {\n    view.selected_package_state.is_some() && view.selected_user.is_some()\n}","tryCatchPattern":"let (Some(package_filter), Some(user)) = (self.selected_package_state, self.selected_user.as_ref()) else { return };","preventionTips":["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."],"tags":["panic","gui","state","null-safety"],"backgroundTag":"null-argument","analyzedSha":"64465c850c7ed36329e67165ac08501abffb218e","analyzedAt":"2026-09-12T09:09:23.137Z","contentChangedAt":"2026-09-12T09:09:23.137Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}