bevyengine/bevy · error

Component already has an on_despawn hook

Error message

Component already has an on_despawn hook

What it means

Panic in ComponentLifecycleHook registration (on_despawn): try_on_despawn found the on_despawn slot already occupied. Only one despawn hook per component is representable, and the expect makes accidental double registration loud rather than silently replacing the first hook.

Source

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

    /// 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> {
        if self.on_add.is_some() {
            return None;
        }
        self.on_add = Some(hook);
        Some(self)
    }

    /// Attempt to register a [`ComponentHook`] that will be run when this component is added (with `.insert`)
    ///
    /// This is a fallible version of [`Self::on_insert`].

View on GitHub (pinned to 396ca72708)

Solutions

  1. Consolidate despawn-time logic into the single registered hook
  2. Search the dependency graph for competing .on_despawn(...) calls on this component
  3. Switch to try_on_despawn when overlap is legitimate
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at crates/bevy_ecs/src/lifecycle.rs:250 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/327cf236a26e85a0. Report an issue: GitHub.