{"record":{"id":"ef0161a93310ffb6","repo":"thanos-io/thanos","slug":"index-header-postingsoffset","errorCode":null,"errorMessage":"index header PostingsOffset","messagePattern":"index header PostingsOffset","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/store/bucket.go","lineNumber":3166,"sourceCode":"\t\t\tl, closer, err := r.decodeCachedPostings(b)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, closeFns, errors.Wrap(err, \"decode postings\")\n\t\t\t}\n\t\t\toutput[ix] = l\n\t\t\tcloseFns = append(closeFns, closer...)\n\t\t\tcontinue\n\t\t}\n\n\t\t// Cache miss; save pointer for actual posting in index stored in object store.\n\t\tptr, err := r.block.indexHeaderReader.PostingsOffset(key.Name, key.Value)\n\t\tif err == indexheader.NotFoundRangeErr {\n\t\t\t// This block does not have any posting for given key.\n\t\t\toutput[ix] = index.EmptyPostings()\n\t\t\tcontinue\n\t\t}\n\n\t\tif err != nil {\n\t\t\treturn nil, closeFns, errors.Wrap(err, \"index header PostingsOffset\")\n\t\t}\n\n\t\tr.stats.postingsToFetch++\n\t\tptrs = append(ptrs, postingPtr{ptr: ptr, keyID: ix})\n\t}\n\n\tsort.Slice(ptrs, func(i, j int) bool {\n\t\treturn ptrs[i].ptr.Start < ptrs[j].ptr.Start\n\t})\n\n\t// TODO(bwplotka): Asses how large in worst case scenario this can be. (e.g fetch for AllPostingsKeys)\n\t// Consider sub split if too big.\n\tparts := r.block.partitioner.Partition(len(ptrs), func(i int) (start, end uint64) {\n\t\treturn uint64(ptrs[i].ptr.Start), uint64(ptrs[i].ptr.End)\n\t})\n\n\tsize = 0\n\tfor _, part := range parts {","sourceCodeStart":3148,"sourceCodeEnd":3184,"githubUrl":"https://github.com/thanos-io/thanos/blob/35b8b991177def87ed52dcf10f9b6d87f07282c8/pkg/store/bucket.go#L3148-L3184","documentation":"When the requested posting list is not in cache, bucketIndexReader asks the block's index header for the byte offset of the postings table for a key. Wrapping an error from that lookup means the index header could not be consulted (or the offset could not be resolved) for postingPtr. This typically indicates the index header itself failed to load or the postings entry referenced does not exist in the block's header.","triggerScenarios":"Calling Postings() with a label name/value whose offset lookup in the loaded index header fails: index header not yet loaded/refreshed for the block, block was deleted or replaced in object storage mid-query, or a corrupted/unsupported index header binary.","commonSituations":"Store-gateway serving a block whose meta was removed from the bucket between listing and querying; race between block removal (compaction) and in-flight queries; corrupted index header file in object storage after a failed upload.","solutions":["Re-sync the store-gateway bucket index so block metadata matches what is actually in object storage","Check the underlying wrapped error: if the block is missing/deleted, drop it from local view and retry the query","Re-upload or restore the block's index (meta.json/index) if the header is corrupted in the bucket","Ensure block deletion uses proper two-step (deletion-mark) flow so readers stop using the block before removal"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"if _, ok := r.block.indexHeader.GetPostingsOffset(name, value); !ok {\n\t// postings offset absent: resync block metadata or skip this block\n}","typeGuard":"func blockServesPosting(ih index.Header, name, value string) bool { _, ok := ih.GetPostingsOffset(name, value); return ok }","tryCatchPattern":"output, closeFns, err := reader.Postings(ctx, tenant, postingGroups...)\nif err != nil && strings.Contains(err.Error(), \"index header PostingsOffset\") {\n\tif rerr := storeGateway.ResyncBlocks(ctx); rerr == nil {\n\t\toutput, closeFns, err = reader.Postings(ctx, tenant, postingGroups...) // retry once after resync\n\t}\n}","preventionTips":["Keep store-gateway bucket index resync enabled with short intervals","Use deletion marks instead of hard-deleting blocks served by readers","Monitor for blocks listed in meta but missing from the bucket","Validate index header uploads complete before advertising blocks"],"tags":["thanos","index-header","object-storage","block"],"backgroundTag":"record-not-found","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"}