bevyengine/bevy · error

Component already has an on_remove hook

Error message

Component already has an on_remove hook

What it means

Panic in ComponentLifecycleHook registration (on_remove): the component already has an on_remove hook stored, so try_on_remove could not install the new one and the expect fired. Same single-slot Option storage guard as the other lifecycle events.

Source

Thrown at crates/bevy_ecs/src/lifecycle.rs:240

    /// As a result, this needs to be combined with immutable components to serve as a mechanism for reliably updating indexes and other caches.
    ///
    /// # Panics
    ///
    /// Will panic if the component already has an `on_discard` hook
    pub fn on_discard(&mut self, hook: ComponentHook) -> &mut Self {
        self.try_on_discard(hook)
            .expect("Component already has an on_discard hook")
    }

    /// Register a [`ComponentHook`] that will be run when this component is removed from an entity.
    /// Despawning an entity counts as removing all of its components.
    ///
    /// # Panics
    ///
    /// Will panic if the component already has an `on_remove` hook
    pub fn on_remove(&mut self, hook: ComponentHook) -> &mut Self {
        self.try_on_remove(hook)
            .expect("Component already has an on_remove hook")
    }

    /// Register a [`ComponentHook`] that will be run for each component on an entity when it is despawned.
    ///
    /// # Panics
    ///
    /// Will panic if the component already has an `on_despawn` hook
    pub fn on_despawn(&mut self, hook: ComponentHook) -> &mut Self {
        self.try_on_despawn(hook)
            .expect("Component already has an on_despawn hook")
    }

    /// Attempt to register a [`ComponentHook`] that will be run when this component is added to an entity.
    ///
    /// This is a fallible version of [`Self::on_add`].
    ///
    /// Returns `None` if the component already has an `on_add` hook.
    pub fn try_on_add(&mut self, hook: ComponentHook) -> Option<&mut Self> {

View on GitHub (pinned to 396ca72708)

Solutions

  1. Register on_remove once; combine multiple concerns in one hook closure
  2. Trace which plugin or configure_hooks call registered the first hook and de-duplicate
  3. Use try_on_remove for cooperative registration
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at crates/bevy_ecs/src/lifecycle.rs:240 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of bevyengine/bevy@396ca72708 (2026-08-20). Data as JSON: /api/errors/f94fe403ebe64c1f. Report an issue: GitHub.