{"record":{"id":"ea8caa14580f65ef","repo":"trekhleb/javascript-algorithms","slug":"item-not-found-in-the-tree","errorCode":null,"errorMessage":"Item not found in the tree","messagePattern":"Item not found in the tree","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/data-structures/tree/binary-search-tree/BinarySearchTreeNode.js","lineNumber":94,"sourceCode":"  }\n\n  /**\n   * @param {*} value\n   * @return {boolean}\n   */\n  contains(value) {\n    return !!this.find(value);\n  }\n\n  /**\n   * @param {*} value\n   * @return {boolean}\n   */\n  remove(value) {\n    const nodeToRemove = this.find(value);\n\n    if (!nodeToRemove) {\n      throw new Error('Item not found in the tree');\n    }\n\n    const { parent } = nodeToRemove;\n\n    if (!nodeToRemove.left && !nodeToRemove.right) {\n      // Node is a leaf and thus has no children.\n      if (parent) {\n        // Node has a parent. Just remove the pointer to this node from the parent.\n        parent.removeChild(nodeToRemove);\n      } else {\n        // Node has no parent. Just erase current node value.\n        nodeToRemove.setValue(undefined);\n      }\n    } else if (nodeToRemove.left && nodeToRemove.right) {\n      // Node has two children.\n      // Find the next biggest value (minimum value in the right branch)\n      // and replace current value node with that next biggest value.\n      const nextBiggerNode = nodeToRemove.right.findMin();","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/trekhleb/javascript-algorithms/blob/85293e3e2b88f4d2ce330d956b139cf628aa1e82/src/data-structures/tree/binary-search-tree/BinarySearchTreeNode.js#L76-L112","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Guard the call: if (tree.contains(value)) tree.remove(value); — contains() is the cheap pre-check for exactly this condition.","If removal is best-effort, wrap remove() in try/catch and treat 'Item not found in the tree' as an idempotent no-op.","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."],"exampleFix":"// before\nbst.remove(42); // throws 'Item not found in the tree' when 42 is absent\n\n// after\nif (bst.contains(42)) {\n  bst.remove(42);\n}","handlingStrategy":"validation","validationCode":"// BinarySearchTree.contains() is the exact pre-check for this throw\nfunction safeRemove(tree, value) {\n  if (!tree.contains(value)) {\n    return false;\n  }\n  return tree.remove(value);\n}","typeGuard":null,"tryCatchPattern":"try {\n  tree.remove(value);\n} catch (e) {\n  if (e.message === 'Item not found in the tree') {\n    return false; // treat as idempotent delete\n  }\n  throw e; // never swallow unrelated errors\n}","preventionTips":["Treat remove() as strict: always pair it with contains() or find() when the value's presence is not guaranteed.","Delete-once patterns: mark ids as processed, or use a Set, so retries do not re-remove.","Normalize value types at the boundary (Number(), String()) so find() sees the same shape that was inserted.","When using a custom comparator, unit-test that insert-then-remove round-trips for every value shape you store."],"tags":["binary-search-tree","remove","item-not-found","data-structures"],"backgroundTag":"item-not-found","analyzedSha":"85293e3e2b88f4d2ce330d956b139cf628aa1e82","analyzedAt":"2026-08-24T05:59:10.417Z","schemaVersion":2},"datasetVersion":"2026-08-24T07:17:09.176Z"}