emilk/egui · error

Plugin of type {:?} not found

Error message

Plugin of type {:?} not found

What it means

`Context::plugin::<T>()` looks up a registered plugin by type and returns a typed handle. If no plugin of type `T` was registered via `context.add_plugin(...)`, the lookup returns None and the method panics with the type name. It exists as a strict accessor; `plugin_opt::<T>()` is the non-panicking variant.

Source

Thrown at crates/egui/src/context.rs:2153

    ///
    /// Returns `None` if the plugin was not registered.
    pub fn with_plugin<T: plugin::Plugin + 'static, R>(
        &self,
        f: impl FnOnce(&mut T) -> R,
    ) -> Option<R> {
        let plugin = self.read(|ctx| ctx.plugins.get(core::any::TypeId::of::<T>()));
        plugin.map(|plugin| f(plugin.lock().typed_plugin_mut()))
    }

    /// Get a handle to the plugin of type `T`.
    ///
    /// ## Panics
    /// If the plugin of type `T` was not registered, this will panic.
    pub fn plugin<T: plugin::Plugin>(&self) -> TypedPluginHandle<T> {
        if let Some(plugin) = self.plugin_opt() {
            plugin
        } else {
            panic!("Plugin of type {:?} not found", core::any::type_name::<T>());
        }
    }

    /// Get a handle to the plugin of type `T`, if it was registered.
    pub fn plugin_opt<T: plugin::Plugin>(&self) -> Option<TypedPluginHandle<T>> {
        let plugin = self.read(|ctx| ctx.plugins.get(core::any::TypeId::of::<T>()));
        plugin.map(TypedPluginHandle::new)
    }

    /// Get a handle to the plugin of type `T`, or insert its default.
    pub fn plugin_or_default<T: plugin::Plugin + Default>(&self) -> TypedPluginHandle<T> {
        if let Some(plugin) = self.plugin_opt() {
            plugin
        } else {
            let default_plugin = T::default();
            self.add_plugin(default_plugin);
            self.plugin()
        }

View on GitHub (pinned to 441971a776)

Solutions

  1. Register the plugin first: call `ctx.add_plugin(MyPlugin::default())` before any `ctx.plugin::<MyPlugin>()` access.
  2. Use `ctx.plugin_opt::<MyPlugin>()` and handle the None case when the plugin may legitimately be absent.
  3. Confirm registration happens on the same `Context` object you're querying (not a re-created or clone-independent one).
  4. Check initialization order: ensure add_plugin runs before the first frame/callback that reads the plugin.

Example fix

// before
let plugin = ctx.plugin::<MyPlugin>(); // panics if not registered
// after
ctx.add_plugin(MyPlugin::default());
let plugin = ctx.plugin::<MyPlugin>();
// or non-panicking:
if let Some(p) = ctx.plugin_opt::<MyPlugin>() { /* use p */ }
Defensive patterns

Strategy: type-guard

Validate before calling

// check registration before strict access
if ctx.plugin_opt::<MyPlugin>().is_none() {
    ctx.add_plugin(MyPlugin::default());
}

Type guard

fn has_plugin<T: egui::plugin::Plugin>(ctx: &egui::Context) -> bool {
    ctx.plugin_opt::<T>().is_some()
}

Try / catch

// Rust panics can't be caught portably (catch_unwind only); prefer:
match ctx.plugin_opt::<MyPlugin>() {
    Some(p) => use(p),
    None => log::warn!("MyPlugin not registered"),
}

Prevention

When it happens

Trigger: Calling `ctx.plugin::<MyPlugin>()` where `ctx.add_plugin(MyPlugin::default())` was never called (or was called on a different Context instance), so `ctx.plugins` has no entry for `TypeId::of::<T>()`.

Common situations: Refactoring that removed the `add_plugin` call while retaining `plugin::<T>()` reads; ordering issues where plugin access happens before registration; sharing state via plugin across two different Context instances.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of emilk/egui@441971a776 (2026-09-12). Data as JSON: /api/errors/ed05a50302451ac3. Report an issue: GitHub.