{"record":{"id":"10f386d2b0636b16","repo":"thanos-io/thanos","slug":"matcherstopostinggroups","errorCode":null,"errorMessage":"matchersToPostingGroups","messagePattern":"matchersToPostingGroups","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/store/bucket.go","lineNumber":2682,"sourceCode":"\tif len(ms) == 0 {\n\t\treturn nil, nil\n\t}\n\n\thit, postings, err := r.fetchExpandedPostingsFromCache(ctx, ms, bytesLimiter, tenant)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif hit {\n\t\treturn newLazyExpandedPostings(postings), nil\n\t}\n\tvar (\n\t\tallRequested = false\n\t\thasAdds      = false\n\t)\n\n\tpostingGroups, err := matchersToPostingGroups(ctx, r.block.indexHeaderReader.LabelValues, ms)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"matchersToPostingGroups\")\n\t}\n\tif postingGroups == nil {\n\t\tr.storeExpandedPostingsToCache(ms, index.EmptyPostings(), 0, tenant)\n\t\treturn nil, nil\n\t}\n\ti := 0\n\tfor _, pg := range postingGroups {\n\t\tallRequested = allRequested || pg.addAll\n\t\thasAdds = hasAdds || len(pg.addKeys) > 0\n\n\t\t// If a posting group doesn't have any keys, like posting group created\n\t\t// from `=~\".*\"`, we don't have to keep the posting group as long as we\n\t\t// keep track of whether we need to add all postings or not.\n\t\tif len(pg.addKeys) == 0 && len(pg.removeKeys) == 0 {\n\t\t\tcontinue\n\t\t}\n\t\tpostingGroups[i] = pg\n\t\ti++","sourceCodeStart":2664,"sourceCodeEnd":2700,"githubUrl":"https://github.com/thanos-io/thanos/blob/35b8b991177def87ed52dcf10f9b6d87f07282c8/pkg/store/bucket.go#L2664-L2700","documentation":"Inside the bucket series set expansion, r (bucketStoreSeriesSet) converts label matchers into posting groups via matchersToPostingGroups, which consults the index header's LabelValues (and possibly the bucket). Any failure there — bad matcher semantics, index-header read failure, missing label values — is wrapped as 'matchersToPostingGroups'. It represents a failure to translate query matchers into index posting lists.","triggerScenarios":"matchersToPostingGroups(ctx, r.block.indexHeaderReader.LabelValues, ms) errors: LabelValues lookup fails on the index header, or the lazy-value-loading func hits object storage and fails, or a matcher references a value that cannot be resolved.","commonSituations":"Corrupt/truncated index-header cache in store-gateway, object storage errors while resolving lazy label values, regex matchers too exotic triggering index lookups that fail, block partially removed mid-query.","solutions":["Check the wrapped inner error for object-store vs index corruption.","Delete stale index-header cache files and let store-gateway re-sync blocks.","Retry the query; transient storage failures resolve on retry.","If a specific matcher reliably fails, simplify it (e.g. replace regex with exact match) and inspect the label's presence in the index."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// pre-check matchers against known label names\nfor _, m := range ms {\n\tif vals, _ := indexHeader.LabelValues(ctx, m.Name); vals == nil {\n\t\t// label absent in this block; skip block early\n\t}\n}","typeGuard":null,"tryCatchPattern":"if err != nil {\n\tif isTransientStorageErr(err) {\n\t\t// retry with backoff\n\t}\n\treturn errors.Wrap(err, \"matchersToPostingGroups\")\n}","preventionTips":["Use exact matchers where possible instead of regex","Keep index-header caches healthy; reload on corruption alerts","Handle absent labels gracefully in query layer"],"tags":["promql-matchers","index-header","thanos-store-gateway"],"backgroundTag":"database-query-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"}