{"record":{"id":"17574f8d43ebf630","repo":"TheAlgorithms/Go","slug":"node-has-too-few-keys","errorCode":null,"errorMessage":"node has too few keys","messagePattern":"node has too few keys","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"structure/tree/btree.go","lineNumber":48,"sourceCode":"\t\tchildren: make([]*BTreeNode[T], maxKeys+1),\n\t\tisLeaf:   isLeaf,\n\t}\n}\n\nfunc NewBTree[T constraints.Ordered](maxKeys int) *BTree[T] {\n\tif maxKeys <= 2 {\n\t\tpanic(\"Must be >= 3 keys\")\n\t}\n\treturn &BTree[T]{\n\t\troot:    nil,\n\t\tmaxKeys: maxKeys,\n\t}\n}\n\nfunc (node *BTreeNode[T]) Verify(tree *BTree[T]) {\n\tminKeys := minKeys(tree.maxKeys)\n\tif node != tree.root && node.numKeys < minKeys {\n\t\tpanic(\"node has too few keys\")\n\t} else if node.numKeys > tree.maxKeys {\n\t\tpanic(\"node has too many keys\")\n\t}\n}\n\nfunc (node *BTreeNode[T]) IsFull(maxKeys int) bool {\n\treturn node.numKeys == maxKeys\n}\n\nfunc (node *BTreeNode[T]) Search(key T) bool {\n\ti := 0\n\tfor ; i < node.numKeys; i++ {\n\t\tif key == node.keys[i] {\n\t\t\treturn true\n\t\t}\n\t\tif key < node.keys[i] {\n\t\t\tbreak\n\t\t}","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/TheAlgorithms/Go/blob/5ba447ec5ff3d1213de65b92e726ee74c5d5cc19/structure/tree/btree.go#L30-L66","documentation":"Verify panics when a non-root node holds fewer keys than minKeys = (maxKeys-1)/2, violating the B-tree minimum occupancy invariant that Delete must maintain via borrow/merge. It indicates the tree's internal rebalancing was bypassed or the node was mutated incorrectly.","triggerScenarios":"Calling Delete on a tree whose nodes were manually mutated (writing to unexported fields via unsafe or reflection); calling DeleteIthKey directly to strip keys below the minimum; reusing nodes across trees with different maxKeys values.","commonSituations":"Mixing nodes between trees constructed with different maxKeys; external code poking at node internals in tests; a version mismatch where helper methods changed their invariants.","solutions":["Use only the public BTree API (Insert/Delete) and never mutate node fields directly.","Ensure all nodes in a tree were created with the same maxKeys as the tree.","Call tree.root.Verify(tree) after suspicious operations to find the invariant break point.","If you need arbitrary key removal, add rebalancing (borrow/merge) after DeleteIthKey."],"exampleFix":"// before\nnode.DeleteIthKey(0) // may underflow the node\n// after\ntree.Delete(key) // maintains B-tree invariants","handlingStrategy":"validation","validationCode":"func (t *BTree[T]) Healthy() bool {\n    defer func() { recover() }()\n    if t.root != nil { t.root.Verify(t) }\n    return true\n}\nif !tree.Healthy() { tree = rebuild(tree) }\ntree.Delete(key)","typeGuard":null,"tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        tree = rebuildTreeFromKeys(tree)\n    }\n}()","preventionTips":["Never mutate BTreeNode fields outside the library","Keep one maxKeys value per tree and its nodes","Verify(root) after any low-level experimentation"],"tags":["panic","btree","invariant-violation"],"backgroundTag":"btree-invariant-violation","analyzedSha":"5ba447ec5ff3d1213de65b92e726ee74c5d5cc19","analyzedAt":"2026-09-02T21:54:30.227Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}