{"record":{"id":"fdc2392c500e17e6","repo":"a-b-street/abstreet","slug":"dropdown-has-default-value-but-none-of-the-choices-match","errorCode":null,"errorMessage":"Dropdown {} has default_value {:?}, but none of the choices match that","messagePattern":"Dropdown (.+?) has default_value (.+?), but none of the choices match that","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"widgetry/src/widgets/dropdown.rs","lineNumber":31,"sourceCode":"    label: String,\n    is_persisten_split: bool,\n\n    choices: Vec<Choice<T>>,\n}\n\nimpl<T: 'static + PartialEq + Clone + std::fmt::Debug> Dropdown<T> {\n    pub fn new(\n        ctx: &EventCtx,\n        label: &str,\n        default_value: T,\n        choices: Vec<Choice<T>>,\n        // TODO Ideally builder style\n        is_persisten_split: bool,\n    ) -> Dropdown<T> {\n        let current_idx = if let Some(idx) = choices.iter().position(|c| c.data == default_value) {\n            idx\n        } else {\n            panic!(\n                \"Dropdown {} has default_value {:?}, but none of the choices match that\",\n                label, default_value\n            );\n        };\n\n        Dropdown {\n            current_idx,\n            btn: make_btn(ctx, &choices[current_idx].label, label, is_persisten_split),\n            menu: None,\n            label: label.to_string(),\n            is_persisten_split,\n            choices,\n        }\n    }\n}\n\nimpl<T: 'static + PartialEq + Clone> Dropdown<T> {\n    pub fn current_value(&self) -> T {","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/a-b-street/abstreet/blob/0964f29315820c91b171b585eb51e300164e9197/widgetry/src/widgets/dropdown.rs#L13-L49","documentation":"Dropdown::new validates that the requested default_value matches one of the provided choices' data; if no choice's data equals default_value it panics. This is a constructor-time invariant so the dropdown can compute its initial selected index.","triggerScenarios":"Calling Dropdown::new (or the widget builder) with choices whose .data values never equal the default_value passed in — including type/equality mismatches (e.g. comparing enum variants not in the list, mismatched IDs after data changes).","commonSituations":"Choices generated dynamically from data while default_value is hardcoded; a refactor changing the data payload so equality no longer holds; default derived from persisted settings that no longer exist in the choice list.","solutions":["Ensure default_value exactly matches one of the choices' data (same value, same PartialEq semantics).","Derive default_value from the choices themselves, e.g. choices[0].data.clone().","If the persisted default may be stale, clamp it to the available choices before constructing.","Consider Dropdown::maybe_new-style tolerant construction if your codebase offers it."],"exampleFix":"// before\nDropdown::new(widget_ctx, \"mode\", vec![Choice::new(\"fast\"), Choice::new(\"slow\")], saved_mode)\n// after\nlet default = choices.iter().map(|c| c.data.clone()).find(|d| *d == saved_mode).unwrap_or_else(|| choices[0].data.clone());\nDropdown::new(widget_ctx, \"mode\", choices, default)","handlingStrategy":"validation","validationCode":"assert!(\n    choices.iter().any(|c| c.data == default_value),\n    \"default {:?} not among choices {:?}\",\n    default_value,\n    choices.iter().map(|c| &c.data).collect::<Vec<_>>()\n);","typeGuard":null,"tryCatchPattern":"let default = if choices.iter().any(|c| c.data == saved) { saved } else { choices[0].data.clone() };\nDropdown::new(ctx, \"label\", choices, default)","preventionTips":["Always derive default_value from the choices list, not external constants","Clamp persisted/old defaults to available choices before constructing","Re-check equality semantics after refactoring the choice data type"],"tags":["rust","widgetry","ui","validation"],"backgroundTag":"invalid-argument-value","analyzedSha":"0964f29315820c91b171b585eb51e300164e9197","analyzedAt":"2026-09-13T18:02:03.421Z","contentChangedAt":"2026-09-13T18:02:03.421Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}