{"record":{"id":"626fa9e1d96d0793","repo":"a-b-street/abstreet","slug":"found-widget-but-wrong-type","errorCode":null,"errorMessage":"Found widget {}, but wrong type","messagePattern":"Found widget (.+?), but wrong type","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"widgetry/src/widgets/panel.rs","lineNumber":484,"sourceCode":"    /// Grab a stashed value and clone it.\n    pub fn clone_stashed<T: 'static + Clone>(&self, name: &str) -> T {\n        self.find::<Stash<T>>(name).get_value().borrow().clone()\n    }\n\n    pub fn is_button_enabled(&self, name: &str) -> bool {\n        self.find::<Button>(name).is_enabled()\n    }\n\n    pub fn maybe_find_widget(&self, name: &str) -> Option<&Widget> {\n        self.top_level.find(name)\n    }\n\n    pub fn maybe_find<T: WidgetImpl>(&self, name: &str) -> Option<&T> {\n        self.maybe_find_widget(name).map(|w| {\n            if let Some(x) = w.widget.downcast_ref::<T>() {\n                x\n            } else {\n                panic!(\"Found widget {}, but wrong type\", name);\n            }\n        })\n    }\n\n    pub fn find<T: WidgetImpl>(&self, name: &str) -> &T {\n        self.maybe_find(name)\n            .unwrap_or_else(|| panic!(\"Can't find widget {}\", name))\n    }\n\n    pub fn find_mut<T: WidgetImpl>(&mut self, name: &str) -> &mut T {\n        if let Some(w) = self.top_level.find_mut(name) {\n            if let Some(x) = w.widget.downcast_mut::<T>() {\n                x\n            } else {\n                panic!(\"Found widget {}, but wrong type\", name);\n            }\n        } else {\n            panic!(\"Can't find widget {}\", name);","sourceCodeStart":466,"sourceCodeEnd":502,"githubUrl":"https://github.com/a-b-street/abstreet/blob/0964f29315820c91b171b585eb51e300164e9197/widgetry/src/widgets/panel.rs#L466-L502","documentation":"`Panel::maybe_find::<T>` looks up a widget by name and downcasts to T; if a widget with that name exists but is a different concrete type than requested, the API contract is broken and it panics instead of returning a confusing reference.","triggerScenarios":"`panel.maybe_find::<Button>(\"x\")` (or `find`) where \"x\" names a Widget of another type, e.g. a Slider or Label — maybe_find_widget succeeds, downcast_ref::<T> fails.","commonSituations":"Changing a widget's type during refactoring (Label -> Button) without updating find calls; two similarly-named widgets; calling find with the wrong generic parameter inferred by the compiler.","solutions":["Annotate the generic type explicitly and match the widget's actual type: maybe_find::<Button>(\"save_btn\")","Rename the widget or update call sites after changing its type","Use maybe_find_widget to inspect the Widget and confirm its type before downcasting"],"exampleFix":"// before\nlet btn = panel.maybe_find::<Slider>(\"save_btn\"); // save_btn is a Button\n// after\nlet btn = panel.maybe_find::<Button>(\"save_btn\");","handlingStrategy":"type-guard","validationCode":"if panel.has_widget(\"save_btn\") {\n    let w = panel.maybe_find_widget(\"save_btn\").unwrap();\n    let is_button = w.widget.downcast_ref::<Button>().is_some();\n}","typeGuard":"fn is_button(panel: &Panel, name: &str) -> bool {\n    panel.maybe_find_widget(name)\n        .map(|w| w.widget.downcast_ref::<Button>().is_some())\n        .unwrap_or(false)\n}","tryCatchPattern":null,"preventionTips":["Annotate generics explicitly at find call sites","Update call sites whenever a widget's type changes","Encode widget type in names"],"tags":["rust","downcast","type-mismatch","panel"],"backgroundTag":"type-mismatch","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"}