{"record":{"id":"b14d6e89fdc0256e","repo":"FyroxEngine/Fyrox","slug":"widget-node-handle-handle-os-event-method-is-a","errorCode":null,"errorMessage":"Widget {node_handle} `handle_os_event` method is already registered!","messagePattern":"Widget (.+?) `handle_os_event` method is already registered!","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"fyrox-ui/src/lib.rs","lineNumber":668,"sourceCode":"\n#[derive(Default, PartialEq, Debug, Clone)]\nstruct WidgetMethodsRegistry {\n    preview_message: FxHashSet<Handle<UiNode>>,\n    on_update: FxHashSet<Handle<UiNode>>,\n    handle_os_event: FxHashSet<Handle<UiNode>>,\n}\n\nimpl WidgetMethodsRegistry {\n    fn register<T: Control + ?Sized>(&mut self, node: &T) {\n        let node_handle = node.handle();\n\n        if node.preview_messages && !self.preview_message.insert(node_handle) {\n            Log::warn(format!(\n                \"Widget {node_handle} `preview_message` method is already registered!\"\n            ));\n        }\n        if node.handle_os_events && !self.handle_os_event.insert(node_handle) {\n            Log::warn(format!(\n                \"Widget {node_handle} `handle_os_event` method is already registered!\"\n            ));\n        }\n        if node.need_update && !self.on_update.insert(node_handle) {\n            Log::warn(format!(\n                \"Widget {node_handle} `on_update` method is already registered!\"\n            ));\n        }\n    }\n\n    fn unregister<T: Control + ?Sized>(&mut self, node: &T) {\n        let node_handle = node.handle();\n\n        self.preview_message.remove(&node_handle);\n        self.on_update.remove(&node_handle);\n        self.handle_os_event.remove(&node_handle);\n    }\n}","sourceCodeStart":650,"sourceCodeEnd":686,"githubUrl":"https://github.com/FyroxEngine/Fyrox/blob/76c91aad8eca488ce527b1af707be8b3b24ad72d/fyrox-ui/src/lib.rs#L650-L686","documentation":"During widget registration the registry inserts the node handle into the handle_os_event set when the widget's handle_os_events flag is true. If the handle is already in the set the widget is being registered a second time, and this warning is logged. It indicates duplicate registration of a widget that handles OS events; behavior is otherwise unaffected.","triggerScenarios":"Calling WidgetMethodsRegistry::register (via the UI's node registration path) twice for the same widget whose Control::handle_os_events returns true — e.g. re-adding a node or double-invoked registration code.","commonSituations":"Custom widgets that respond to keyboard/mouse OS events being re-registered by plugin reload or builder misuse; adding the same node handle to the UI graph twice.","solutions":["Ensure register() is called only once per widget instance.","Call unregister() on widget removal so re-adds don't collide with stale set entries.","Deduplicate your registration code path (e.g. use a HashSet or builder state to check before registering).","Ignore if benign, but resolve to keep method routing correct."],"exampleFix":"// before\nfn on_rebuild(&mut self, ui) {\n    self.register(ui); // runs every rebuild for an already-registered widget\n}\n// after\nfn on_rebuild(&mut self, ui) {\n    if !self.is_registered {\n        self.register(ui);\n        self.is_registered = true;\n    }\n}","handlingStrategy":"validation","validationCode":"let newly = self.registered_os_event_handles.insert(node.handle());\nif newly { ui.register_widget(node); }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep registration idempotent in rebuild/reload paths.","Unregister widgets before re-registering.","Only enable handle_os_events on widgets that truly need it.","Audit custom Control impls for double registration calls."],"tags":["gui","duplicate-registration","lifecycle"],"backgroundTag":"invalid-state-transition","analyzedSha":"76c91aad8eca488ce527b1af707be8b3b24ad72d","analyzedAt":"2026-09-10T16:04:01.633Z","contentChangedAt":"2026-09-10T16:04:01.633Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}