FyroxEngine/Fyrox · error

The handle must be valid

Error message

The handle must be valid

What it means

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.

Solutions

  1. Only use handles obtained from graph.generate_free_handle() (or public add_node APIs that reserve internally)
  2. Reserve a fresh handle with take_reserve if you need to link children by known handle
  3. Do not persist and reuse handles across different Graph instances

Example fix

// before
let handle = Handle::new(42, 0);
graph.add_node(node, handle);

// after
let handle = graph.generate_free_handle();
graph.add_node(node, handle);
Defensive patterns

Strategy: validation

Validate before calling

// reserve handles only from the same graph
let handle = graph.generate_free_handle();

Try / catch

// invariant violation; use public add_node APIs that reserve handles internally instead of catch

Prevention

When it happens

Trigger: 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.

Common situations: Custom graph-copy/deserialization code generating handles manually; handles serialized from an older graph reused in a new graph instance.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of FyroxEngine/Fyrox@76c91aad8e (2026-09-10). Data as JSON: /api/errors/7b01bf88b9b2ff39. Report an issue: GitHub.

Appendix: source

Thrown at fyrox-graph/src/lib.rs:1956

        }

        fn add_node(&mut self, node: Self::NodeWrapper) -> Handle<Self::NodeWrapper> {
            let handle = self.nodes.next_free_handle();
            self.add_node_at_handle(node, handle);
            handle
        }

        fn add_node_at_handle(
            &mut self,
            mut node: Self::NodeWrapper,
            handle: Handle<Self::NodeWrapper>,
        ) {
            let children = node.children.clone();
            node.children.clear();
            let handle = self
                .nodes
                .spawn_at_handle(handle, node)
                .expect("The handle must be valid");

            if self.root.is_none() {
                self.root = handle;
            } else {
                self.link_nodes(handle, self.root);
            }

            for child in children {
                self.link_nodes(child, handle);
            }

            let node = &mut self.nodes[handle];
            node.self_handle = handle;
        }

        fn remove_node(&mut self, node_handle: Handle<impl ObjectOrVariant<Self::NodeWrapper>>) {
            let node_handle = node_handle.to_base();
            self.isolate_node(node_handle);

View on GitHub (pinned to 76c91aad8e)