{"record":{"id":"8bbf56ee46129095","repo":"ethereum/go-ethereum","slug":"unknown-layer-type-t","errorCode":null,"errorMessage":"unknown layer type: %T","messagePattern":"unknown layer type: %T","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"triedb/pathdb/difflayer.go","lineNumber":189,"sourceCode":"\t\t\treturn nil, err\n\t\t}\n\t\tdl.parent = result\n\t\tdl.lock.Unlock()\n\t}\n\treturn diffToDisk(dl, force)\n}\n\n// size returns the approximate memory size occupied by this diff layer.\nfunc (dl *diffLayer) size() uint64 {\n\treturn dl.nodes.size + dl.states.size\n}\n\n// diffToDisk merges a bottom-most diff into the persistent disk layer underneath\n// it. The method will panic if called onto a non-bottom-most diff layer.\nfunc diffToDisk(layer *diffLayer, force bool) (*diskLayer, error) {\n\tdisk, ok := layer.parentLayer().(*diskLayer)\n\tif !ok {\n\t\tpanic(fmt.Sprintf(\"unknown layer type: %T\", layer.parentLayer()))\n\t}\n\treturn disk.commit(layer, force)\n}\n","sourceCodeStart":171,"sourceCodeEnd":193,"githubUrl":"https://github.com/ethereum/go-ethereum/blob/6bb0588ad8e7f922e4ad5580f51265a4097af08f/triedb/pathdb/difflayer.go#L171-L193","documentation":"diffToDisk merges a bottom-most in-memory diffLayer into the diskLayer beneath it; it requires layer.parentLayer() to be a *diskLayer. If the parent is still another diffLayer (or something else entirely), the layer stack is inconsistent — flattening should have collapsed intermediate diffs first — so the code panics with the actual parent type in the message.","triggerScenarios":"Calling diffToDisk on a diffLayer that is not bottom-most, i.e. whose parent is another diffLayer. In stock geth this is reached only through internal checkpoint/commit logic; a panic means the layer list got out of order (e.g. truncation while new diffs were added, or concurrent layer mutation).","commonSituations":"Bugs in pathdb layer truncation (reset/rollback) racing with new block commits; forks calling internal persistence functions directly; history/pruning configuration interactions that skip the flatten step.","solutions":["Read the %T in the panic message: *diffLayer means flattening was skipped; something else means the stack holds a foreign layer type","Ensure all triedb reset/truncate/commit operations hold the pathdb lock and cannot interleave","Don't call diffToDisk from fork code; drive persistence via the public Commit/Checkpoint APIs which maintain ordering","If reproducible on unmodified geth, capture layer heights in the panic and report upstream"],"exampleFix":"// before\ndiffToDisk(dl, true) // panics when dl.parent is another *diffLayer\n\n// after\n// only ever persist the bottom-most diff, after flattening\nfor parent, ok := dl.parentLayer().(*diffLayer); ok; parent, ok = parent.parentLayer().(*diffLayer) {\n    dl = parent\n}\ndiffToDisk(dl, true)","handlingStrategy":"validation","validationCode":"// Fork code: flatten to the bottom-most diff before persisting\nfunc bottomMost(dl *pathdb.diffLayer) *pathdb.diffLayer {\n    for {\n        p, ok := dl.parentLayer().(*pathdb.diffLayer)\n        if !ok { return dl }\n        dl = p\n    }\n}","typeGuard":"func parentIsDisk(dl *diffLayer) bool {\n    _, ok := dl.parentLayer().(*diskLayer)\n    return ok\n}","tryCatchPattern":"defer func() {\n    if r := recover(); r != nil {\n        err = fmt.Errorf(\"layer stack inconsistent at diffToDisk: %v\", r)\n    }\n}()\n_, err = diffToDisk(dl, force)","preventionTips":["Use only public Reset/Commit/Checkpoint entry points so layer ordering holds","Hold the pathdb lock across any sequence of truncate+commit","On panic, dump the layer chain (types and heights) before restarting"],"tags":["pathdb","triedb","layer-stack","state-corruption","panic"],"backgroundTag":null,"analyzedSha":"6bb0588ad8e7f922e4ad5580f51265a4097af08f","analyzedAt":"2026-08-15T10:06:53.996Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}