{"record":{"id":"2e31043ccb5d08d9","repo":"bevyengine/bevy","slug":"component-already-has-an-on-discard-hook","errorCode":null,"errorMessage":"Component already has an on_discard hook","messagePattern":"Component already has an on_discard hook","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/bevy_ecs/src/lifecycle.rs","lineNumber":229,"sourceCode":"    /// such as being replaced (with `.insert`) or removed.\n    ///\n    /// If this component is inserted onto an entity that already has it, this hook will run before the value is replaced,\n    /// allowing access to the previous data just before it is dropped.\n    /// This hook does *not* run if the entity did not already have this component.\n    ///\n    /// An `on_discard` hook always runs before any `on_remove` hooks (if the component is being removed from the entity).\n    ///\n    /// # Warning\n    ///\n    /// The hook won't run if the component is already present and is only mutated, such as in a system via a query.\n    /// As a result, this needs to be combined with immutable components to serve as a mechanism for reliably updating indexes and other caches.\n    ///\n    /// # Panics\n    ///\n    /// Will panic if the component already has an `on_discard` hook\n    pub fn on_discard(&mut self, hook: ComponentHook) -> &mut Self {\n        self.try_on_discard(hook)\n            .expect(\"Component already has an on_discard hook\")\n    }\n\n    /// Register a [`ComponentHook`] that will be run when this component is removed from an entity.\n    /// Despawning an entity counts as removing all of its components.\n    ///\n    /// # Panics\n    ///\n    /// Will panic if the component already has an `on_remove` hook\n    pub fn on_remove(&mut self, hook: ComponentHook) -> &mut Self {\n        self.try_on_remove(hook)\n            .expect(\"Component already has an on_remove hook\")\n    }\n\n    /// Register a [`ComponentHook`] that will be run for each component on an entity when it is despawned.\n    ///\n    /// # Panics\n    ///\n    /// Will panic if the component already has an `on_despawn` hook","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/bevyengine/bevy/blob/396ca727080776bd313bb892423b7d94e03b81b4/crates/bevy_ecs/src/lifecycle.rs#L211-L247","documentation":"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.","triggerScenarios":"Thrown at crates/bevy_ecs/src/lifecycle.rs:229 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","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"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"396ca727080776bd313bb892423b7d94e03b81b4","analyzedAt":"2026-08-20T16:12:39.808Z","contentChangedAt":"2026-08-20T16:12:39.808Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}