a-b-street/abstreet · error

Found widget , but wrong type

Error message

Found widget {}, but wrong type

What it means

`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.

Solutions

  1. Annotate the generic type explicitly and match the widget's actual type: maybe_find::<Button>("save_btn")
  2. Rename the widget or update call sites after changing its type
  3. Use maybe_find_widget to inspect the Widget and confirm its type before downcasting

Example fix

// before
let btn = panel.maybe_find::<Slider>("save_btn"); // save_btn is a Button
// after
let btn = panel.maybe_find::<Button>("save_btn");
Defensive patterns

Strategy: type-guard

Validate before calling

if panel.has_widget("save_btn") {
    let w = panel.maybe_find_widget("save_btn").unwrap();
    let is_button = w.widget.downcast_ref::<Button>().is_some();
}

Type guard

fn is_button(panel: &Panel, name: &str) -> bool {
    panel.maybe_find_widget(name)
        .map(|w| w.widget.downcast_ref::<Button>().is_some())
        .unwrap_or(false)
}

Prevention

When it happens

Trigger: `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.

Common situations: 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.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of a-b-street/abstreet@0964f29315 (2026-09-13). Data as JSON: /api/errors/626fa9e1d96d0793. Report an issue: GitHub.

Appendix: source

Thrown at widgetry/src/widgets/panel.rs:484

    /// Grab a stashed value and clone it.
    pub fn clone_stashed<T: 'static + Clone>(&self, name: &str) -> T {
        self.find::<Stash<T>>(name).get_value().borrow().clone()
    }

    pub fn is_button_enabled(&self, name: &str) -> bool {
        self.find::<Button>(name).is_enabled()
    }

    pub fn maybe_find_widget(&self, name: &str) -> Option<&Widget> {
        self.top_level.find(name)
    }

    pub fn maybe_find<T: WidgetImpl>(&self, name: &str) -> Option<&T> {
        self.maybe_find_widget(name).map(|w| {
            if let Some(x) = w.widget.downcast_ref::<T>() {
                x
            } else {
                panic!("Found widget {}, but wrong type", name);
            }
        })
    }

    pub fn find<T: WidgetImpl>(&self, name: &str) -> &T {
        self.maybe_find(name)
            .unwrap_or_else(|| panic!("Can't find widget {}", name))
    }

    pub fn find_mut<T: WidgetImpl>(&mut self, name: &str) -> &mut T {
        if let Some(w) = self.top_level.find_mut(name) {
            if let Some(x) = w.widget.downcast_mut::<T>() {
                x
            } else {
                panic!("Found widget {}, but wrong type", name);
            }
        } else {
            panic!("Can't find widget {}", name);

View on GitHub (pinned to 0964f29315)