{"record":{"id":"10fb19a6d85bb754","repo":"microsoft/typescript-go","slug":"at-node-d-kind-v-w","errorCode":null,"errorMessage":"at node %d (kind %v): %w","messagePattern":"at node (.+?) \\(kind (.+?)\\): %w","errorType":"validation","errorClass":"ErrClientError","httpStatus":null,"severity":"error","filePath":"internal/api/encoder/decoder.go","lineNumber":172,"sourceCode":"\t\tdata := d.nodeField(i, NodeOffsetData)\n\t\tchildIndices := d.collectChildren(i)\n\n\t\tif kind == SyntaxKindNodeList {\n\t\t\tchildNodes := d.allocNodeSlice(len(childIndices))\n\t\t\tfor _, ci := range childIndices {\n\t\t\t\tif d.nodes[ci] != nil {\n\t\t\t\t\tchildNodes = append(childNodes, d.nodes[ci])\n\t\t\t\t}\n\t\t\t}\n\t\t\tnl := d.factory.NewNodeList(childNodes)\n\t\t\tnl.Loc = core.NewTextRange(int(pos), int(end))\n\t\t\td.nodeLists[i] = nl\n\t\t\tcontinue\n\t\t}\n\n\t\tnode, err := d.createNode(ast.Kind(kind), data, childIndices)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"at node %d (kind %v): %w\", i, ast.Kind(kind), err)\n\t\t}\n\t\tnode.Loc = core.NewTextRange(int(pos), int(end))\n\t\tnode.Flags = ast.NodeFlags(d.nodeField(i, NodeOffsetFlags))\n\t\td.nodes[i] = node\n\t}\n\n\treturn d.nodes[1], nil\n}\n\n// getModifierList creates a *ast.ModifierList from a child index that is a NodeList.\nfunc (d *astDecoder) getModifierList(ci int) *ast.ModifierList {\n\tnl := d.nodeLists[ci]\n\tif nl == nil {\n\t\treturn nil\n\t}\n\tml := d.factory.NewModifierList(nl.Nodes)\n\tml.Loc = nl.Loc\n\treturn ml","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/microsoft/typescript-go/blob/1bcfa18d79a3be41772223d5c05dfe4480e614ff/internal/api/encoder/decoder.go#L154-L190","documentation":"Wrapper error from the bottom-up node reconstruction loop: node i (index and syntax kind are printed) failed in createNode. The wrapped error comes from the generated tables - 'unknown string node kind', 'unknown extended data node kind', or 'unhandled node kind with N children' - meaning the kind/data bytes map to no constructor this build knows.","triggerScenarios":"Version skew where the encoder emitted a syntax kind or data-type tag this decoder's generated tables don't cover; bit-flipped kind fields in a corrupted blob; truncation making the last node's fields read as garbage.","commonSituations":"Upgrading one side of a pair that exchanges encoded ASTs; long-lived caches surviving an upgrade; fuzzed or checksum-less transport of blobs.","solutions":["Pin encoder and decoder to the exact same typescript-go build and re-encode","Regenerate stored fixtures/caches after any upgrade","Use the printed node index and kind diagnostically: one wildly large kind means corruption; many failures across kinds means version skew","Add integrity verification before decoding blobs from untrusted sources"],"exampleFix":"// before\nclient := newClient(serverV6) // encodes with newer kind table\nserver := newServer(libV5)     // decodes with older table\n\n// after\nclient := newClient(libV5)\nserver := newServer(libV5) // same build on both ends","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"sf, err := encoder.DecodeSourceFile(data)\nif err != nil {\n\tvar idx int; var kind ast.Kind\n\tif _, e := fmt.Sscanf(err.Error(), \"at node %d (kind %v)\", &idx, &kind); e == nil {\n\t\tlog.Printf(\"blob incompatible or corrupt at node %d (kind %v); re-encoding\", idx, kind)\n\t\treturn reparseAndEncode(source)\n\t}\n\treturn nil, err\n}","preventionTips":["Pin both sides of an AST exchange to the same library build","Regenerate caches/fixtures after upgrades","Verify checksums before decoding untrusted blobs"],"tags":["go","ast","encoder","version-skew","corruption","decoding"],"backgroundTag":null,"analyzedSha":"1bcfa18d79a3be41772223d5c05dfe4480e614ff","analyzedAt":"2026-08-16T02:12:00.115Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}