donnemartin/interactive-coding-challenges · error · TypeError

node cannot be None

Error message

node cannot be None

What it means

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.

Source

Thrown at graphs_trees/bst_successor/bst_successor_solution.ipynb:114

   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "%run ../bst/bst.py"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "class BstSuccessor(object):\n",
    "\n",
    "    def get_next(self, node):\n",
    "        if node is None:\n",
    "            raise TypeError('node cannot be None')\n",
    "        if node.right is not None:\n",
    "            return self._left_most(node.right)\n",
    "        else:\n",
    "            return self._next_ancestor(node)\n",
    "\n",
    "    def _left_most(self, node):\n",
    "        if node.left is not None:\n",
    "            return self._left_most(node.left)\n",
    "        else:\n",
    "            return node.data\n",
    "\n",
    "    def _next_ancestor(self, node):\n",
    "        if node.parent is not None:\n",
    "            if node.parent.data > node.data:\n",
    "                return node.parent.data\n",
    "            else:\n",
    "                return self._next_ancestor(node.parent)\n",
    "        # We reached the root, the original input node\n",

View on GitHub (pinned to 358f2cc604)

Solutions

  1. Check for None between chained get_next calls and stop the loop
  2. Guard the argument: if node is None: break/return before calling
  3. Use the return value's None-ness as the end-of-traversal signal

Example fix

# before
node = root
while True:
    node = succ.get_next(node)  # crashes when node is None

# after
node = root
while node is not None:
    process(node)
    node = succ.get_next(node) if node is not root else succ.get_next(node)
# simpler: check before each call
node = succ.get_next(root)
while node is not None:
    process(node)
    node = succ.get_next(node)
Defensive patterns

Strategy: type-guard

Validate before calling

if node is None:
    return None  # end of traversal
successor.get_next(node)

Type guard

def is_node(n) -> bool:
    return n is not None

Try / catch

try:
    nxt = succ.get_next(node)
except TypeError as e:
    if 'cannot be None' in str(e):
        nxt = None  # treat as end of tree
    else:
        raise

Prevention

When it happens

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

Common situations: Iterating a BST via successor calls without a termination check; traversals that assume another node exists past the maximum element.

Related errors


AI-assisted analysis of donnemartin/interactive-coding-challenges@358f2cc604 (2026-08-28). Data as JSON: /api/errors/abea0977e4f57f47. Report an issue: GitHub.