thanos-io/thanos · error
read series
Error message
read series
What it means
Wraps IndexReader.LoadSeriesForTime failure in blockSeriesClient.series. This step decodes each preloaded series' symbols and chunk metadata, filtering by the query time range (mint/maxt). Failure indicates corrupt or unreadable series data in the block index.
Solutions
- Identify the failing block via the wrapped error and run 'thanos tools bucket verify'.
- Delete or restore the corrupted block so the compactor re-uploads a healthy copy.
- Check for storage-layer bit rot (object-store checksum features, disk health on store gateway cache dirs).
- Confirm all components run Prometheus/Thanos versions with compatible index formats.
Defensive patterns
Strategy: fallback
Try / catch
if err := query(ctx); err != nil && strings.Contains(err.Error(), "read series") {
logger.Error("series decode failed; possible corrupt block", "err", err)
// fall back to partial results or failover to another store instance
return failoverQuery(ctx, q)
} Prevention
- Enable object-store checksums to detect bit rot at rest.
- Run 'thanos tools bucket verify' regularly and quarantine corrupt blocks.
- Keep compactor, store gateway, and Prometheus index versions aligned.
- Monitor store gateway memory to prevent reader-cache corruption under pressure.
When it happens
Trigger: For each posting batch entry, indexr.LoadSeriesForTime(posting, &symbolizedLset, &chkMetas, skipChunks, mint, maxt) errors while decoding a series entry or its chunk metadata from the index.
Common situations: Bit-corrupted index files (bad disk/object store), blocks written by mismatched Prometheus index versions, memory pressure corrupting reader caches.
Understand the failure class
Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.
Related errors
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/6413611977cc8b2f.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/store/bucket.go:1318
b.indexr.reset(len(postingsBatch))
if !b.skipChunks {
b.chunkr.reset()
}
if err := b.indexr.PreloadSeries(b.ctx, postingsBatch, b.bytesLimiter, b.tenant); err != nil {
return errors.Wrap(err, "preload series")
}
seriesMatched := 0
b.entries = b.entries[:0]
OUTER:
for i := range postingsBatch {
if err := b.ctx.Err(); err != nil {
return err
}
hasMatchedChunks, err := b.indexr.LoadSeriesForTime(postingsBatch[i], &b.symbolizedLset, &b.chkMetas, b.skipChunks, b.mint, b.maxt)
if err != nil {
return errors.Wrap(err, "read series")
}
// Skip getting series symbols if we know there is no matched chunks
// and lazy expanded posting not enabled.
if !lazyExpandedPosting && !hasMatchedChunks {
continue
}
if err := b.indexr.LookupLabelsSymbols(b.ctx, b.symbolizedLset, b.b); err != nil {
return errors.Wrap(err, "Lookup labels symbols")
}
b.lset = b.b.Labels()
for _, matcher := range b.lazyPostings.matchers {
val := b.lset.Get(matcher.Name)
if !matcher.Matches(val) {
// Series not matched means series we overfetched due to lazy posting expansion.
seriesBytes := b.indexr.loadedSeries[postingsBatch[i]]
b.lazyExpandedPostingSeriesOverfetchedSizeBytes.Add(float64(len(seriesBytes)))View on GitHub (pinned to 35b8b99117)