{"record":{"id":"62681a887dc33fc6","repo":"TheAlgorithms/Go","slug":"called-insertnonfull-with-a-full-node","errorCode":null,"errorMessage":"Called InsertNonFull() with a full node","messagePattern":"Called InsertNonFull\\(\\) with a full node","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"structure/tree/btree.go","lineNumber":152,"sourceCode":"\n\t// Reuse child as the left node\n\tchild.numKeys = midKeyIndex\n\n\t// Insert the child's mid index to the parent\n\tfor i := parent.numKeys; i > idx; i-- {\n\t\tparent.keys[i] = parent.keys[i-1]\n\t\tparent.children[i+1] = parent.children[i]\n\t}\n\tparent.keys[idx] = child.keys[midKeyIndex]\n\tparent.children[idx] = child\n\tparent.children[idx+1] = rightChild\n\tparent.numKeys += 1\n}\n\nfunc (node *BTreeNode[T]) InsertNonFull(tree *BTree[T], key T) {\n\tnode.Verify(tree)\n\tif node.IsFull(tree.maxKeys) {\n\t\tpanic(\"Called InsertNonFull() with a full node\")\n\t}\n\n\tif node.isLeaf {\n\t\t// Node is a leaf. Directly insert the key.\n\t\tnode.InsertKeyChild(key, nil)\n\t\treturn\n\t}\n\n\t// Find the child node to insert into\n\ti := 0\n\tfor ; i < node.numKeys; i++ {\n\t\tif key < node.keys[i] {\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif node.children[i].IsFull(tree.maxKeys) {\n\t\tnode.Split(i, tree.maxKeys)","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/TheAlgorithms/Go/blob/5ba447ec5ff3d1213de65b92e726ee74c5d5cc19/structure/tree/btree.go#L134-L170","documentation":"InsertNonFull must only be called on a node that is not full; the method checks IsFull first and panics if the node already holds maxKeys. It is an internal invariant — callers (the tree itself) are responsible for splitting full children before recursing.","triggerScenarios":"Calling node.InsertNonFull(tree, key) directly on a node with numKeys == maxKeys without splitting first; misuse of the exported node-level API on the root when the tree should have split the root first.","commonSituations":"Custom insert loops in application code that call node methods instead of tree.Insert; tests reaching into internals; a new root created without the split being performed.","solutions":["Call tree.Insert(key) instead of node.InsertNonFull directly — it handles root splitting.","If calling InsertNonFull on a child, check node.IsFull(tree.maxKeys) and call Split first.","Add a wrapper in your code that splits the root when full before recursing."],"exampleFix":"// before\nif tree.root.IsFull(tree.maxKeys) { /* forgot split */ }\ntree.root.InsertNonFull(tree, key)\n// after\ntree.Insert(key)","handlingStrategy":"try-catch","validationCode":"if tree.root != nil && tree.root.IsFull(tree.maxKeys) {\n    // split root first or just use tree.Insert\n}\ntree.Insert(key)","typeGuard":null,"tryCatchPattern":"func safeInsertNonFull[T constraints.Ordered](n *BTreeNode[T], t *BTree[T], k T) (err error) {\n    defer func() {\n        if r := recover(); r != nil { err = fmt.Errorf(\"insert failed: %v\", r) }\n    }()\n    if n.IsFull(t.maxKeys) { return errors.New(\"node full; split first\") }\n    n.InsertNonFull(t, k)\n    return nil\n}","preventionTips":["Prefer tree.Insert over node-level APIs","Split before recursing into full children","Keep custom rebalancing minimal and tested"],"tags":["panic","btree","precondition-failed"],"backgroundTag":"precondition-violated","analyzedSha":"5ba447ec5ff3d1213de65b92e726ee74c5d5cc19","analyzedAt":"2026-09-02T21:54:30.227Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}