bevyengine/bevy · error
Component already has an on_discard hook
Error message
Component already has an on_discard hook
What it means
Panic in ComponentLifecycleHook registration (on_discard): try_on_discard returned None, meaning an on_discard hook is already stored for this component. The expect enforces one hook per lifecycle event since the storage holds an Option, not a list.
Source
Thrown at crates/bevy_ecs/src/lifecycle.rs:229
/// such as being replaced (with `.insert`) or removed.
///
/// If this component is inserted onto an entity that already has it, this hook will run before the value is replaced,
/// allowing access to the previous data just before it is dropped.
/// This hook does *not* run if the entity did not already have this component.
///
/// An `on_discard` hook always runs before any `on_remove` hooks (if the component is being removed from the entity).
///
/// # Warning
///
/// The hook won't run if the component is already present and is only mutated, such as in a system via a query.
/// 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` hookView on GitHub (pinned to 396ca72708)
Solutions
- Fold additional logic into the existing on_discard hook
- Locate and remove the earlier .on_discard(...) registration (often from another plugin)
- Prefer try_on_discard with explicit conflict handling in library code
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at crates/bevy_ecs/src/lifecycle.rs:229 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/2e31043ccb5d08d9.
Report an issue: GitHub.