{"record":{"id":"0cd238fdcc5ddd32","repo":"Textualize/textual","slug":"unknown-nodeid-node-id-in-tree","errorCode":null,"errorMessage":"Unknown NodeID ({node_id}) in tree","messagePattern":"Unknown NodeID \\((.+?)\\) in tree","errorType":"exception","errorClass":"UnknownNodeID","httpStatus":null,"severity":"error","filePath":"src/textual/widgets/_tree.py","lineNumber":1050,"sourceCode":"        else:\n            return line.node\n\n    def get_node_by_id(self, node_id: NodeID) -> TreeNode[TreeDataType]:\n        \"\"\"Get a tree node by its ID.\n\n        Args:\n            node_id: The ID of the node to get.\n\n        Returns:\n            The node associated with that ID.\n\n        Raises:\n            UnknownNodeID: Raised if the `TreeNode` ID is unknown.\n        \"\"\"\n        try:\n            return self._tree_nodes[node_id]\n        except KeyError:\n            raise UnknownNodeID(f\"Unknown NodeID ({node_id}) in tree\") from None\n\n    def validate_cursor_line(self, value: int) -> int:\n        \"\"\"Prevent cursor line from going outside of range.\n\n        Args:\n            value: The value to test.\n\n        Return:\n            A valid version of the given value.\n        \"\"\"\n        return clamp(value, 0, len(self._tree_lines) - 1)\n\n    def validate_guide_depth(self, value: int) -> int:\n        \"\"\"Restrict guide depth to reasonable range.\n\n        Args:\n            value: The value to test.\n","sourceCodeStart":1032,"sourceCodeEnd":1068,"githubUrl":"https://github.com/Textualize/textual/blob/06dbeef4bb70fb718236aa418ed658ef4667a126/src/textual/widgets/_tree.py#L1032-L1068","documentation":"UnknownNodeID from Tree.get_node_by_id(): the requested NodeID is not present in the tree's node registry (self._tree_nodes). The node was likely removed or the tree cleared/reloaded, regenerating IDs.","triggerScenarios":"`tree.get_node_by_id(node_id)` after `tree.clear()`, after `node.remove()` on the target, or with an ID captured from a previous build of the tree.","commonSituations":"Storing NodeIDs in app state (e.g. selection persistence) across tree rebuilds; handling Tree.NodeSelected with a delayed lookup after mutation.","solutions":["Wrap the lookup in try/except UnknownNodeID and handle absence gracefully.","Re-derive IDs after clear()/reload; prefer stable business keys in node.data rather than NodeIDs.","Check `tree._tree_nodes` membership or use `get_node_by_id` immediately when the event arrives."],"exampleFix":"# before\nnode = tree.get_node_by_id(saved_id)\n# after\ntry:\n    node = tree.get_node_by_id(saved_id)\nexcept UnknownNodeID:\n    node = None","handlingStrategy":"try-catch","validationCode":"if node_id in tree._tree_nodes:\n    node = tree.get_node_by_id(node_id)","typeGuard":null,"tryCatchPattern":"from textual.widgets._tree import UnknownNodeID\ntry:\n    node = tree.get_node_by_id(node_id)\nexcept UnknownNodeID:\n    node = None","preventionTips":["Look up nodes immediately when events arrive","Keep stable keys in node.data and rebuild lookups after clear()"],"tags":["tree","node-id","lookup","textual"],"backgroundTag":"stale-node-reference","analyzedSha":"06dbeef4bb70fb718236aa418ed658ef4667a126","analyzedAt":"2026-08-27T02:36:57.214Z","schemaVersion":2},"datasetVersion":"2026-08-27T03:17:27.898Z"}