{"record":{"id":"531700aace7efd0f","repo":"ethereum/go-ethereum","slug":"unexpected-node-type-t","errorCode":null,"errorMessage":"unexpected node type, %T","messagePattern":"unexpected node type, %T","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"trie/hasher.go","lineNumber":101,"sourceCode":"\t\tif len(enc) < 32 && !force {\n\t\t\t// Nodes smaller than 32 bytes are embedded directly in their parent.\n\t\t\t// In such cases, return the raw encoded blob instead of the node hash.\n\t\t\t// It's essential to deep-copy the node blob, as the underlying buffer\n\t\t\t// of enc will be reused later.\n\t\t\tbuf := make([]byte, len(enc))\n\t\t\tcopy(buf, enc)\n\t\t\treturn buf\n\t\t}\n\t\thash := h.hashData(enc)\n\t\tn.flags.hash = hash\n\t\treturn hash\n\n\tcase hashNode:\n\t\t// hash nodes don't have children, so they're left as were\n\t\treturn n\n\n\tdefault:\n\t\tpanic(fmt.Errorf(\"unexpected node type, %T\", n))\n\t}\n}\n\n// encodeShortNode encodes the provided shortNode into the bytes. Notably, the\n// return slice must be deep-copied explicitly, otherwise the underlying slice\n// will be reused later.\nfunc (h *hasher) encodeShortNode(n *shortNode) []byte {\n\t// Encode leaf node\n\tif hasTerm(n.Key) {\n\t\tvar ln leafNodeEncoder\n\t\tln.Key = hexToCompact(n.Key)\n\t\tln.Val = n.Val.(valueNode)\n\t\tln.encode(h.encbuf)\n\t\treturn h.encodedBytes()\n\t}\n\t// Encode extension node\n\tvar en extNodeEncoder\n\ten.Key = hexToCompact(n.Key)","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/ethereum/go-ethereum/blob/6bb0588ad8e7f922e4ad5580f51265a4097af08f/trie/hasher.go#L83-L119","documentation":"The Merkle-Patricia-trie hasher panics on a node type outside its switch (shortNode, fullNode, valueNode, hashNode are handled; anything else hits default). This is an internal invariant violation: the trie node graph only ever contains those four types, so reaching default means memory corruption, a hand-constructed node, or an internal bug.","triggerScenarios":"Inserting a custom type satisfying the node interface into trie internals; a corrupted or race-mutated trie structure passed to hashing; a fork/modified trie package introducing a new node type without updating the hasher.","commonSituations":"Running a patched or forked trie with new node kinds; data races mutating trie nodes concurrently (unsynchronized concurrent trie writes); memory corruption from unsafe code; version skew between trie subpackages compiled together.","solutions":["If you forked or extended node types, update hasher.go's switch to handle the new type.","Audit for concurrent access to a single trie instance; use one trie per goroutine or Copy() per goroutine.","Rebuild/re-sync the trie from the database to discard in-memory corruption.","Report upstream with a stack trace if it occurs on unmodified code."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        err = fmt.Errorf(\"trie hashing invariant violated: %v\", r)\n    }\n}()\nroot := t.Hash() // convert panic into error at your API boundary","preventionTips":["Never mutate or share a trie across goroutines; give each goroutine its own trie or a Copy().","If you fork the trie and add node types, update every type switch (hasher, stats, inspector).","Run with -race during development to catch concurrent trie access early."],"tags":["trie","hashing","invariant-violation","internal","corruption","panic","go"],"backgroundTag":null,"analyzedSha":"6bb0588ad8e7f922e4ad5580f51265a4097af08f","analyzedAt":"2026-08-15T10:06:53.996Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}