{"record":{"id":"1a986c7bd4d68e46","repo":"thanos-io/thanos","slug":"snappy-decode","errorCode":null,"errorMessage":"snappy decode","messagePattern":"snappy decode","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/store/postings_codec.go","lineNumber":486,"sourceCode":"\tif !isDiffVarintSnappyEncodedPostings(input) {\n\t\treturn nil, errors.New(\"header not found\")\n\t}\n\n\ttoFree := make([][]byte, 0, 2)\n\n\tvar dstBuf []byte\n\tif !disablePooling {\n\t\tif len, err := s2.DecodedLen(input[len(codecHeaderSnappy):]); err == nil {\n\t\t\tif decodeBuf, err := snappyDecodePool.Get(len); err == nil && decodeBuf != nil {\n\t\t\t\tdstBuf = *decodeBuf\n\t\t\t\ttoFree = append(toFree, dstBuf)\n\t\t\t}\n\t\t}\n\t}\n\n\traw, err := s2.Decode(dstBuf, input[len(codecHeaderSnappy):])\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"snappy decode\")\n\t}\n\n\tif !alias(raw, dstBuf) && !disablePooling {\n\t\ttoFree = append(toFree, raw)\n\t}\n\n\treturn newDiffVarintPostings(raw, toFree), nil\n}\n\nfunc newDiffVarintPostings(input []byte, freeSlices [][]byte) *diffVarintPostings {\n\treturn &diffVarintPostings{freeSlices: freeSlices, buf: &encoding.Decbuf{B: input}}\n}\n\n// diffVarintPostings is an implementation of index.Postings based on diff+varint encoded data.\ntype diffVarintPostings struct {\n\tbuf        *encoding.Decbuf\n\tcur        storage.SeriesRef\n\tfreeSlices [][]byte","sourceCodeStart":468,"sourceCodeEnd":504,"githubUrl":"https://github.com/thanos-io/thanos/blob/35b8b991177def87ed52dcf10f9b6d87f07282c8/pkg/store/postings_codec.go#L468-L504","documentation":"The decoder calls s2.Decode to decompress the postings body and wraps any decode failure in an error with the message \"snappy decode\". This means the compressed payload after the codec header is not valid Snappy/s2 data — truncated, corrupted, or not Snappy-compressed at all.","triggerScenarios":"diffVarintSnappyDecode receives input whose body fails s2.Decode: corrupted bytes, truncated buffer, wrong slice start (skipping the header but keeping misaligned payload), or data compressed with an incompatible setting.","commonSituations":"Corrupted block files on disk, incomplete downloads/copies, byte-offset mistakes when slicing the index section, or mixing formats between Prometheus versions.","solutions":["Re-copy or re-download the affected block/section and retry; verify checksums to rule out transfer corruption.","Confirm the slice offset: input must be the full postings blob including the codec header, with s2 payload starting at input[len(codecHeaderSnappy):].","Run `promtool check blocks` to identify corrupt blocks and remove/restore them.","Check storage integrity (disk SMART, filesystem) if corruption recurs."],"exampleFix":"// before\nraw, err := diffVarintSnappyDecode(input[3:], false) // misaligned slice\n// after\nraw, err := diffVarintSnappyDecode(input, false) // full blob incl. header","handlingStrategy":"try-catch","validationCode":"if len(input) <= len(codecHeaderSnappy) {\n    return errors.New(\"postings payload too short to decode\")\n}","typeGuard":null,"tryCatchPattern":"p, err := diffVarintSnappyDecode(input, false)\nif err != nil {\n    var s2Err s2Error\n    if errors.As(err, &s2Err) || strings.Contains(err.Error(), \"snappy decode\") {\n        // payload corrupt/truncated: refetch block\n    }\n}","preventionTips":["Pass the complete blob including codec header so the s2 payload is correctly aligned.","Verify checksums on every block transfer or download.","Treat truncation (short reads) as corruption; re-copy the source.","Run promtool check blocks on storage to catch corruption early."],"tags":["go","snappy","postings","decoding","corruption"],"backgroundTag":"snappy-decode-failed","analyzedSha":"35b8b991177def87ed52dcf10f9b6d87f07282c8","analyzedAt":"2026-09-07T01:49:59.689Z","contentChangedAt":"2026-09-07T01:49:59.689Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}