{"record":{"id":"7b01bf88b9b2ff39","repo":"FyroxEngine/Fyrox","slug":"the-handle-must-be-valid-7b01bf","errorCode":null,"errorMessage":"The handle must be valid","messagePattern":"The handle must be valid","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"fyrox-graph/src/lib.rs","lineNumber":1956,"sourceCode":"        }\n\n        fn add_node(&mut self, node: Self::NodeWrapper) -> Handle<Self::NodeWrapper> {\n            let handle = self.nodes.next_free_handle();\n            self.add_node_at_handle(node, handle);\n            handle\n        }\n\n        fn add_node_at_handle(\n            &mut self,\n            mut node: Self::NodeWrapper,\n            handle: Handle<Self::NodeWrapper>,\n        ) {\n            let children = node.children.clone();\n            node.children.clear();\n            let handle = self\n                .nodes\n                .spawn_at_handle(handle, node)\n                .expect(\"The handle must be valid\");\n\n            if self.root.is_none() {\n                self.root = handle;\n            } else {\n                self.link_nodes(handle, self.root);\n            }\n\n            for child in children {\n                self.link_nodes(child, handle);\n            }\n\n            let node = &mut self.nodes[handle];\n            node.self_handle = handle;\n        }\n\n        fn remove_node(&mut self, node_handle: Handle<impl ObjectOrVariant<Self::NodeWrapper>>) {\n            let node_handle = node_handle.to_base();\n            self.isolate_node(node_handle);","sourceCodeStart":1938,"sourceCodeEnd":1974,"githubUrl":"https://github.com/FyroxEngine/Fyrox/blob/76c91aad8eca488ce527b1af707be8b3b24ad72d/fyrox-graph/src/lib.rs#L1938-L1974","documentation":"Graph::add_node (internal node insertion) spawns the node at a pre-reserved handle. The handle was expected to be reserved beforehand (via generate_free_handle/is_valid_handle), so spawning should always succeed; if the pool reports the handle invalid, an internal invariant is broken and the code panics.","triggerScenarios":"Passing a handle that was never reserved from this graph's pool, or reusing a handle already consumed; typically only reachable through misuse of generate_free_handle/add_node pairs rather than public add_node with fresh handles.","commonSituations":"Custom graph-copy/deserialization code generating handles manually; handles serialized from an older graph reused in a new graph instance.","solutions":["Only use handles obtained from graph.generate_free_handle() (or public add_node APIs that reserve internally)","Reserve a fresh handle with take_reserve if you need to link children by known handle","Do not persist and reuse handles across different Graph instances"],"exampleFix":"// before\nlet handle = Handle::new(42, 0);\ngraph.add_node(node, handle);\n\n// after\nlet handle = graph.generate_free_handle();\ngraph.add_node(node, handle);","handlingStrategy":"validation","validationCode":"// reserve handles only from the same graph\nlet handle = graph.generate_free_handle();","typeGuard":null,"tryCatchPattern":"// invariant violation; use public add_node APIs that reserve handles internally instead of catch","preventionTips":["Only use handles from generate_free_handle or public node-creation APIs","Never deserialize raw handle indices into a fresh Graph","Prefer add_node returning its own handle over pre-computed handles"],"tags":["panic","graph","handle","invariant"],"backgroundTag":"internal-invariant-violation","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"}