{"record":{"id":"abea0977e4f57f47","repo":"donnemartin/interactive-coding-challenges","slug":"node-cannot-be-none","errorCode":null,"errorMessage":"node cannot be None","messagePattern":"node cannot be None","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"graphs_trees/bst_successor/bst_successor_solution.ipynb","lineNumber":114,"sourceCode":"   \"cell_type\": \"code\",\n   \"execution_count\": 1,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"%run ../bst/bst.py\"\n   ]\n  },\n  {\n   \"cell_type\": \"code\",\n   \"execution_count\": 2,\n   \"metadata\": {},\n   \"outputs\": [],\n   \"source\": [\n    \"class BstSuccessor(object):\\n\",\n    \"\\n\",\n    \"    def get_next(self, node):\\n\",\n    \"        if node is None:\\n\",\n    \"            raise TypeError('node cannot be None')\\n\",\n    \"        if node.right is not None:\\n\",\n    \"            return self._left_most(node.right)\\n\",\n    \"        else:\\n\",\n    \"            return self._next_ancestor(node)\\n\",\n    \"\\n\",\n    \"    def _left_most(self, node):\\n\",\n    \"        if node.left is not None:\\n\",\n    \"            return self._left_most(node.left)\\n\",\n    \"        else:\\n\",\n    \"            return node.data\\n\",\n    \"\\n\",\n    \"    def _next_ancestor(self, node):\\n\",\n    \"        if node.parent is not None:\\n\",\n    \"            if node.parent.data > node.data:\\n\",\n    \"                return node.parent.data\\n\",\n    \"            else:\\n\",\n    \"                return self._next_ancestor(node.parent)\\n\",\n    \"        # We reached the root, the original input node\\n\",","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/donnemartin/interactive-coding-challenges/blob/358f2cc60426d5c4c3d7d580910eec9a7b393fa9/graphs_trees/bst_successor/bst_successor_solution.ipynb#L96-L132","documentation":"BstSuccessor.get_next raises TypeError('node cannot be None') when the node argument is None. The routine immediately dereferences node.right to find the in-order successor, so a None node is rejected before that access.","triggerScenarios":"succ.get_next(None), or get_next(succ.get_next(current)) when current was the last node in the tree and get_next returned None, chaining calls in a traversal loop.","commonSituations":"Iterating a BST via successor calls without a termination check; traversals that assume another node exists past the maximum element.","solutions":["Check for None between chained get_next calls and stop the loop","Guard the argument: if node is None: break/return before calling","Use the return value's None-ness as the end-of-traversal signal"],"exampleFix":"# before\nnode = root\nwhile True:\n    node = succ.get_next(node)  # crashes when node is None\n\n# after\nnode = root\nwhile node is not None:\n    process(node)\n    node = succ.get_next(node) if node is not root else succ.get_next(node)\n# simpler: check before each call\nnode = succ.get_next(root)\nwhile node is not None:\n    process(node)\n    node = succ.get_next(node)","handlingStrategy":"type-guard","validationCode":"if node is None:\n    return None  # end of traversal\nsuccessor.get_next(node)","typeGuard":"def is_node(n) -> bool:\n    return n is not None","tryCatchPattern":"try:\n    nxt = succ.get_next(node)\nexcept TypeError as e:\n    if 'cannot be None' in str(e):\n        nxt = None  # treat as end of tree\n    else:\n        raise","preventionTips":["Always loop with 'while node is not None' in successor traversals","Treat a None successor result as the termination signal","Never chain get_next() without an intermediate None check"],"tags":["python","bst","successor","tree-traversal","none-check"],"backgroundTag":"none-argument-type-error","analyzedSha":"358f2cc60426d5c4c3d7d580910eec9a7b393fa9","analyzedAt":"2026-08-28T10:16:54.480Z","schemaVersion":2},"datasetVersion":"2026-08-28T11:17:15.048Z"}