trekhleb/javascript-algorithms · error · Error

Item not found in the tree

Error message

Item not found in the tree

What it means

BinarySearchTreeNode.remove(value) begins with find(value); when find returns null it throws 'Item not found in the tree' rather than returning false. BinarySearchTree.remove just delegates to the root node, so removing any value the tree does not contain — including on an empty tree — raises this error. It is a fail-fast contract: the caller is expected to have verified the value exists.

Source

Thrown at src/data-structures/tree/binary-search-tree/BinarySearchTreeNode.js:94

  }

  /**
   * @param {*} value
   * @return {boolean}
   */
  contains(value) {
    return !!this.find(value);
  }

  /**
   * @param {*} value
   * @return {boolean}
   */
  remove(value) {
    const nodeToRemove = this.find(value);

    if (!nodeToRemove) {
      throw new Error('Item not found in the tree');
    }

    const { parent } = nodeToRemove;

    if (!nodeToRemove.left && !nodeToRemove.right) {
      // Node is a leaf and thus has no children.
      if (parent) {
        // Node has a parent. Just remove the pointer to this node from the parent.
        parent.removeChild(nodeToRemove);
      } else {
        // Node has no parent. Just erase current node value.
        nodeToRemove.setValue(undefined);
      }
    } else if (nodeToRemove.left && nodeToRemove.right) {
      // Node has two children.
      // Find the next biggest value (minimum value in the right branch)
      // and replace current value node with that next biggest value.
      const nextBiggerNode = nodeToRemove.right.findMin();

View on GitHub (pinned to 85293e3e2b)

Solutions

  1. Guard the call: if (tree.contains(value)) tree.remove(value); — contains() is the cheap pre-check for exactly this condition.
  2. If removal is best-effort, wrap remove() in try/catch and treat 'Item not found in the tree' as an idempotent no-op.
  3. If the value should exist, debug the lookup: print tree.toString(), verify the value's type, and check that the constructor's comparator treats the stored and passed values as equal.

Example fix

// before
bst.remove(42); // throws 'Item not found in the tree' when 42 is absent

// after
if (bst.contains(42)) {
  bst.remove(42);
}
Defensive patterns

Strategy: validation

Validate before calling

// BinarySearchTree.contains() is the exact pre-check for this throw
function safeRemove(tree, value) {
  if (!tree.contains(value)) {
    return false;
  }
  return tree.remove(value);
}

Try / catch

try {
  tree.remove(value);
} catch (e) {
  if (e.message === 'Item not found in the tree') {
    return false; // treat as idempotent delete
  }
  throw e; // never swallow unrelated errors
}

Prevention

When it happens

Trigger: bst.remove(x) where x was never inserted; removing from an empty tree; deleting the same value twice in a row; removing a value whose type differs from the stored one ('42' vs 42); using a custom nodeValueCompareFunction whose equality branch disagrees with how values were inserted, so find() misses a node that is visually present.

Common situations: Cleanup loops deleting ids that may already be gone; retry or duplicate request handlers calling remove twice; values parsed from JSON where numbers arrive as strings; comparator or config drift between the insert and remove paths.

Related errors


AI-assisted analysis of trekhleb/javascript-algorithms@85293e3e2b (2026-08-24). Data as JSON: /api/errors/ea8caa14580f65ef. Report an issue: GitHub.