emilk/egui · error
app_mut got the wrong type of App
Error message
app_mut got the wrong type of App
What it means
AppRunner::app_mut downcasts the boxed App to a caller-chosen concrete type via App::as_any_mut. The .expect fires when the downcast_mut::<ConcreteApp>() returns None, i.e. the stored App instance is not actually of the requested type. The library panics because there is no way to return a typed reference safely when the caller names the wrong type.
Source
Thrown at crates/eframe/src/web/app_runner.rs:192
.native_pixels_per_point = Some(super::native_pixels_per_point());
runner.input.raw.system_theme = super::system_theme();
Ok(runner)
}
pub fn egui_ctx(&self) -> &egui::Context {
&self.egui_ctx
}
/// Get mutable access to the concrete [`App`] we enclose.
///
/// This will panic if your app does not implement [`App::as_any_mut`].
pub fn app_mut<ConcreteApp: 'static + App>(&mut self) -> &mut ConcreteApp {
self.app
.as_any_mut()
.expect("Your app must implement `as_any_mut`, but it doesn't")
.downcast_mut::<ConcreteApp>()
.expect("app_mut got the wrong type of App")
}
pub fn auto_save_if_needed(&mut self) {
let time_since_last_save = now_sec() - self.last_save_time;
if time_since_last_save > self.app.auto_save_interval().as_secs_f64() {
self.save();
}
}
pub fn save(&mut self) {
if self.app.persist_egui_memory() {
super::storage::save_memory(&self.egui_ctx);
}
if let Some(storage) = self.frame.storage_mut() {
self.app.save(storage);
}
self.last_save_time = now_sec();
}View on GitHub (pinned to 441971a776)
Solutions
- Make the generic parameter of app_mut exactly the concrete type the runner was constructed with (e.g. app_mut::<MyApp>()).
- Verify App::as_any_mut is implemented as `self` on the concrete app (#[inline] fn as_any_mut(&mut self) -> &mut dyn Any { self }), not on a wrapper.
- Search for other constructions of the runner to find which App type is actually stored.
Example fix
// before let app = runner.app_mut::<OldApp>(); // after let app = runner.app_mut::<MyApp>();
Defensive patterns
Strategy: type-guard
Validate before calling
fn app_is<T: 'static + App>(runner: &AppRunner) -> bool { runner.app().as_any().is::<T>() } Type guard
fn as_concrete<T: 'static + App>(runner: &mut AppRunner) -> Option<&mut T> { runner.app_mut::<T>() }.ok()
// safer: check first: runner.app().as_any().downcast_ref::<T>().is_some() Try / catch
// Rust panics; use std::panic::catch_unwind only at integration boundaries, otherwise ensure the concrete type via downcast_ref check before app_mut.
Prevention
- Always pass the exact concrete App type used to construct the runner.
- Implement as_any_mut as `self` on the concrete App only.
- Add a debug_assert using downcast_ref before calling app_mut in test code.
When it happens
Trigger: Calling runner.app_mut::<MyApp>() where the runner was created with a different concrete App type (or a wrapper/box type that doesn't downcast to MyApp), typically because as_any_mut returns self but the generic parameter doesn't match the constructed app.
Common situations: Copy-pasting app_mut calls from examples into a project whose App type was renamed; running multiple apps and passing the wrong runner; wrapping the App in a newtype that forwards as_any_mut incorrectly; using app_mut in tests with a mock app of a different type.
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
- Your app must implement `as_any_mut`, but it doesn't
- Failed to read {}: {}
- {err}
- Harness::ui_id is only available for harnesses built with a
- Unsupported value for UPDATE_SNAPSHOTS: {unknown:?}
AI-assisted analysis of emilk/egui@441971a776 (2026-09-12).
Data as JSON: /api/errors/deafd202eb824a76.
Report an issue: GitHub.