{"record":{"id":"3964c676272fac5e","repo":"microsoft/typescript-go","slug":"unsupported-protocol-version-d-expected-d","errorCode":null,"errorMessage":"unsupported protocol version %d (expected %d)","messagePattern":"unsupported protocol version (.+?) \\(expected (.+?)\\)","errorType":"validation","errorClass":"ErrClientError","httpStatus":null,"severity":"error","filePath":"internal/api/encoder/decoder.go","lineNumber":59,"sourceCode":"\treturn node.AsSourceFile(), nil\n}\n\n// DecodeNodes decodes binary-encoded AST data into a tree of *ast.Node objects.\nfunc DecodeNodes(data []byte) (*ast.Node, error) {\n\td, err := newASTDecoder(data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn d.decode()\n}\n\nfunc newASTDecoder(data []byte) (*astDecoder, error) {\n\tif len(data) < HeaderSize {\n\t\treturn nil, fmt.Errorf(\"data too short for header: %d bytes\", len(data))\n\t}\n\tversion := data[HeaderOffsetMetadata+3]\n\tif version != ProtocolVersion {\n\t\treturn nil, fmt.Errorf(\"unsupported protocol version %d (expected %d)\", version, ProtocolVersion)\n\t}\n\n\tstrTable := readLE32(data, HeaderOffsetStringOffsets)\n\tstrData := readLE32(data, HeaderOffsetStringData)\n\textData := readLE32(data, HeaderOffsetExtendedData)\n\tnodeOff := readLE32(data, HeaderOffsetNodes)\n\n\tdataLen := uint32(len(data))\n\n\t// Validate that all offsets are within the buffer.\n\tif strTable > dataLen || strData > dataLen || extData > dataLen || nodeOff > dataLen {\n\t\treturn nil, fmt.Errorf(\"invalid AST header offsets: offsets exceed data length (%d)\", dataLen)\n\t}\n\n\t// Validate monotonic non-decreasing order of regions.\n\tif !(strTable <= strData && strData <= extData && extData <= nodeOff) {\n\t\treturn nil, fmt.Errorf(\"invalid AST header offsets: expected strTable <= strData <= extData <= nodeOff (got %d, %d, %d, %d)\", strTable, strData, extData, nodeOff)\n\t}","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/microsoft/typescript-go/blob/1bcfa18d79a3be41772223d5c05dfe4480e614ff/internal/api/encoder/decoder.go#L41-L77","documentation":"Byte 3 of the buffer (the high byte of the metadata header word) carries the encoder protocol version and must equal encoder.ProtocolVersion. A mismatch means the blob was written by a different, binary-incompatible build of the AST encoder; the layout cannot be trusted.","triggerScenarios":"Decoding with an older or newer typescript-go build than the one that encoded the AST; blobs persisted to disk or cache across an upgrade; hand-crafted buffers with a wrong metadata word.","commonSituations":"Server upgraded while a client or cache still holds old blobs; two copies of the library with different versions in one process; CI replaying recorded fixtures after a version bump.","solutions":["Re-encode the AST with the current build (re-parse the source file)","Pin encoder and decoder to the same typescript-go version on both ends of the exchange","Version-stamp cache entries and invalidate them on library upgrade","Regenerate binary fixtures with the new encoder after upgrading"],"exampleFix":"// before\ncacheKey := fmt.Sprintf(\"ast:%s\", fileName) // survives upgrades badly\n\n// after\ncacheKey := fmt.Sprintf(\"ast:v%d:%s\", encoder.ProtocolVersion, fileName)","handlingStrategy":"validation","validationCode":"if len(data) > encoder.HeaderOffsetMetadata+3 &&\n\tdata[encoder.HeaderOffsetMetadata+3] != encoder.ProtocolVersion {\n\t// stale blob: re-encode instead of decode\n\treturn reparseAndEncode(source)\n}\nreturn encoder.DecodeSourceFile(data)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pin encoder and decoder to the same typescript-go build","Include ProtocolVersion in cache keys","Regenerate binary fixtures after upgrades"],"tags":["go","versioning","encoder","binary","compatibility","cache"],"backgroundTag":null,"analyzedSha":"1bcfa18d79a3be41772223d5c05dfe4480e614ff","analyzedAt":"2026-08-16T02:12:00.115Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}