{"record":{"id":"fed5db95d1268a30","repo":"bevyengine/bevy","slug":"component-already-has-an-on-add-hook","errorCode":null,"errorMessage":"Component already has an on_add hook","messagePattern":"Component already has an on_add hook","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/bevy_ecs/src/lifecycle.rs","lineNumber":189,"sourceCode":"            self.on_remove(hook);\n        }\n        if let Some(hook) = C::on_despawn() {\n            self.on_despawn(hook);\n        }\n\n        self\n    }\n\n    /// Register a [`ComponentHook`] that will be run when this component is added to an entity.\n    /// An `on_add` hook will always run before `on_insert` hooks. Spawning an entity counts as\n    /// adding all of its components.\n    ///\n    /// # Panics\n    ///\n    /// Will panic if the component already has an `on_add` hook\n    pub fn on_add(&mut self, hook: ComponentHook) -> &mut Self {\n        self.try_on_add(hook)\n            .expect(\"Component already has an on_add hook\")\n    }\n\n    /// Register a [`ComponentHook`] that will be run when this component is added (with `.insert`)\n    /// or replaced.\n    ///\n    /// An `on_insert` hook always runs after any `on_add` hooks (if the entity didn't already have the component).\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_insert` hook\n    pub fn on_insert(&mut self, hook: ComponentHook) -> &mut Self {\n        self.try_on_insert(hook)\n            .expect(\"Component already has an on_insert hook\")","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/bevyengine/bevy/blob/396ca727080776bd313bb892423b7d94e03b81b4/crates/bevy_ecs/src/lifecycle.rs#L171-L207","documentation":"Panic in ComponentLifecycleHook registration (on_add): try_on_add returned None because the component's lifecycle storage already holds an on_add hook. Registering a second hook for the same event would silently drop one, so the builder method uses expect as a guard against double registration.","triggerScenarios":"Thrown at crates/bevy_ecs/src/lifecycle.rs:189 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Register each hook kind once per component; consolidate logic into the existing hook closure","Remove a prior .on_add(...) call or plugin that already registered the hook","Use try_on_add to handle pre-existing hooks gracefully instead of panicking"],"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"}