donnemartin/interactive-coding-challenges · error · TypeError

root cannot be None

Error message

root cannot be None

What it means

BinaryTreeOptimized.lca raises TypeError('root cannot be None') when the root argument is None; the algorithm needs a non-empty tree to compute the lowest common ancestor. This differs from sibling implementations that return None, so read the signature carefully: root is a parameter here, not an attribute.

Source

Thrown at graphs_trees/tree_lca/tree_lca_solution.ipynb:168

  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "class LcaResult(object):\n",
    "\n",
    "    def __init__(self, node, is_ancestor):\n",
    "        self.node = node\n",
    "        self.is_ancestor = is_ancestor\n",
    "\n",
    "\n",
    "class BinaryTreeOptimized(object):\n",
    "\n",
    "    def lca(self, root, node1, node2):\n",
    "        if root is None:\n",
    "            raise TypeError('root cannot be None')\n",
    "        result = self._lca(root, node1, node2)\n",
    "        if result.is_ancestor:\n",
    "            return result.node\n",
    "        return None\n",
    "\n",
    "    def _lca(self, curr_node, node1, node2):\n",
    "        if curr_node is None:\n",
    "            return LcaResult(None, is_ancestor=False)\n",
    "        if curr_node is node1 and curr_node is node2:\n",
    "            return LcaResult(curr_node, is_ancestor=True)\n",
    "        left_result = self._lca(curr_node.left, node1, node2)\n",
    "        if left_result.is_ancestor:\n",
    "            return left_result\n",
    "        right_result = self._lca(curr_node.right, node1, node2)\n",
    "        if right_result.is_ancestor:\n",
    "            return right_result\n",
    "        if left_result.node is not None and right_result.node is not None:\n",
    "            return LcaResult(curr_node, is_ancestor=True)\n",

View on GitHub (pinned to 358f2cc604)

Solutions

  1. Ensure root is a real Node before calling lca (build the tree from non-empty data)
  2. Guard: if root is not None: result = tree.lca(root, n1, n2)
  3. Catch TypeError in tests covering the empty-tree edge case

Example fix

// before
result = solution.lca(tree_root, node1, node2)  # TypeError if tree_root is None
// after
if tree_root is not None:
    result = solution.lca(tree_root, node1, node2)
else:
    result = None
Defensive patterns

Strategy: type-guard

Validate before calling

if root is None:
    return None
return solution.lca(root, node1, node2)

Type guard

def is_node(x) -> bool:
    return x is not None and hasattr(x, 'left') and hasattr(x, 'right')

Try / catch

try:
    return solution.lca(root, node1, node2)
except TypeError:
    return None  # empty tree has no LCA

Prevention

When it happens

Trigger: Calling lca(None, node1, node2), or passing a tree's root that was never assigned (empty tree built from empty input).

Common situations: Constructing test trees via a helper that returns None for empty arrays, or switching from another LCA implementation in this repo that silently handles None roots, creating mismatched expectations.

Related errors


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