TheAlgorithms/Python · error · ValueError

Value {value} not found

Error message

Value {value} not found

What it means

Raised by BinarySearchTree.remove() in data_structures/binary_tree/binary_search_tree.py when search(value) returns None — the value is not present in the tree. remove() locates the node first and refuses to silently no-op, raising ValueError with the missing value in the message.

Source

Thrown at data_structures/binary_tree/binary_search_tree.py:285

        >>> BinarySearchTree().insert(1, 783, 30, 740, 1).get_min()
        {'1': (None, {'783': ({'30': (1, 740)}, None)})}
        """
        if node is None:
            node = self.root
        if self.root is None:
            return None
        if not self.empty():
            node = self.root
            while node.left is not None:
                node = node.left
        return node

    def remove(self, value: int) -> None:
        # Look for the node with that label
        node = self.search(value)
        if node is None:
            msg = f"Value {value} not found"
            raise ValueError(msg)

        if node.left is None and node.right is None:  # If it has no children
            self.__reassign_nodes(node, None)
        elif node.left is None:  # Has only right children
            self.__reassign_nodes(node, node.right)
        elif node.right is None:  # Has only left children
            self.__reassign_nodes(node, node.left)
        else:
            predecessor = self.get_max(
                node.left
            )  # Gets the max value of the left branch
            self.remove(predecessor.value)  # type: ignore[union-attr]
            node.value = (
                predecessor.value  # type: ignore[union-attr]
            )  # Assigns the value to the node to delete and keep tree structure

    def preorder_traverse(self, node: Node | None) -> Iterable:
        if node is not None:

View on GitHub (pinned to f5988cc097)

Solutions

  1. Check membership before removing: use `if value in tree` (or search) and skip when absent.
  2. Wrap remove in try/except ValueError for bulk operations where absence is expected.
  3. Make delete handlers idempotent so a second delete of the same value is a no-op.

Example fix

# before
tree.remove(42)  # 42 not in tree

# after
if 42 in tree:
    tree.remove(42)
Defensive patterns

Strategy: try-catch

Validate before calling

if value in tree:
    tree.remove(value)

Try / catch

try:
    tree.remove(value)
except ValueError as e:
    if 'not found' in str(e):
        pass  # idempotent delete
    else:
        raise

Prevention

When it happens

Trigger: Calling remove(42) on a tree that does not contain 42; also removing an already-removed value, or removing from an empty tree (search raises IndexError first in that case — the not-found path applies once the tree has nodes).

Common situations: Double-removal in UIs (two delete clicks for the same item), bulk deletion where the source list contains duplicates the tree does not, or cleanup code that assumes a value exists without checking.

Related errors


AI-assisted analysis of TheAlgorithms/Python@f5988cc097 (2026-08-14). Data as JSON: /api/errors/b213cc4066806d9b. Report an issue: GitHub.