donnemartin/interactive-coding-challenges · error · ValueError

root must have at least one child

Error message

root must have at least one child

What it means

Bst.find_second_largest raises ValueError('root must have at least one child') when the tree consists of a single node (root with no left and no right child). With only one node there is no second largest element, so the state is invalid rather than merely empty.

Source

Thrown at graphs_trees/bst_second_largest/bst_second_largest_solution.ipynb:160

    "        if node.right is not None:\n",
    "            if node.right.left is not None or node.right.right is not None:\n",
    "                return self._find_second_largest(node.right)\n",
    "            else:\n",
    "                return node\n",
    "        else:\n",
    "            return self._find_right_most_node(node.left)\n",
    "\n",
    "    def _find_right_most_node(self, node):\n",
    "        if node.right is not None:\n",
    "            return self._find_right_most_node(node.right)\n",
    "        else:\n",
    "            return node\n",
    "\n",
    "    def find_second_largest(self):\n",
    "        if self.root is None:\n",
    "            raise TypeError('root cannot be None')\n",
    "        if self.root.right is None and self.root.left is None:\n",
    "            raise ValueError('root must have at least one child')\n",
    "        return self._find_second_largest(self.root)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Unit Test"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",

View on GitHub (pinned to 358f2cc604)

Solutions

  1. Insert at least two elements before calling find_second_largest()
  2. Guard the call: check tree.root and one of tree.root.left/tree.root.right exist first
  3. Wrap with your own accessor that returns None for single-node trees

Example fix

# before
bst.insert(10)
second = bst.find_second_largest()  # only one node

# after
bst.insert(10)
bst.insert(4)
second = bst.find_second_largest()
Defensive patterns

Strategy: validation

Validate before calling

root = bst.root
if root is None or (root.left is None and root.right is None):
    return None  # fewer than two nodes
bst.find_second_largest()

Type guard

def has_at_least_two_nodes(t) -> bool:
    return t.root is not None and (t.root.left is not None or t.root.right is not None)

Try / catch

try:
    second = bst.find_second_largest()
except ValueError as e:
    if 'at least one child' in str(e):
        second = None
    else:
        raise

Prevention

When it happens

Trigger: bst.insert(5); bst.find_second_largest() on a tree containing exactly one node — root.right is None and root.left is None.

Common situations: Querying small datasets, early in ingestion when only one record has arrived, or test cases that only insert a single element.

Related errors


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