thanos-io/thanos · error

series

Error message

series

What it means

This error wraps a failure from IndexReader.Series(id, &builder, &chks) in block.Rewrite (pkg/block/index.go:615) while iterating each posting ID to rebuild series. It means the series section of the source index cannot be resolved for a specific series ID — the label set or chunk metas for that posting are unreadable. Because rewrite iterates every posting, a single corrupt series entry fails the whole rewrite.

Solutions

  1. Identify the failing series ID from the wrapped inner error; if isolated, use promtool tsdb analyze or drop/rewrite the specific block.
  2. Restore the block from backup or another replica; individual corrupt series entries generally cannot be repaired in place.
  3. Quarantine (move out) the corrupt block so TSDB marks it and continues operating; re-fetch the affected time range from remote storage.
  4. If many series fail, treat the whole index as corrupt and prefer full block re-download over Repair.

Example fix

// before: one bad series aborts entire repair
if err := indexr.Series(id, &builder, &chks); err != nil { return errors.Wrap(err, "series") }
// after: tolerate isolated failures during repair by skipping bad IDs
if err := indexr.Series(id, &builder, &chks); err != nil {
    log.Warn("skipping unreadable series in rewrite", "id", id, "err", err)
    continue
}
Defensive patterns

Strategy: try-catch

Validate before calling

all, err := indexr.Postings(ctx, index.AllPostingsKey())
if err != nil { return err }
it := indexr.SortedPostings(all)
for it.Next() { if _, err := indexr.Series(it.At()); err != nil { log.Warn("unreadable series", "id", it.At()) } }

Type guard

func isSeriesError(err error) bool { return err != nil && strings.Contains(err.Error(), "series") }

Try / catch

if err := block.Rewrite(ctx, meta, src, dst, indexr, chunkr, nil); err != nil {
    var seriesErr bool
    if strings.Contains(err.Error(), "series") { seriesErr = true }
    if seriesErr { /* identify failing id from wrapped cause, skip or restore block */ }
    return err
}

Prevention

When it happens

Trigger: For a given posting ID from the all-postings iterator, indexr.Series() fails decoding the label builder or chunk metadata (bad offset into the series section, invalid varint, out-of-range reference).

Common situations: Repairing blocks where individual series entries were corrupted by crash/incomplete write; blocks after disk errors; partially recovered block directories where index sections reference each other inconsistently.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07). Data as JSON: /api/errors/4c5c045c7f7892c2. Report an issue: GitHub.

Appendix: source

Thrown at pkg/block/index.go:615

		return errors.Wrap(err, "postings")
	}
	all = indexr.SortedPostings(all)

	// We fully rebuild the postings list index from merged series.
	var (
		postings = index.NewMemPostings()
		values   = map[string]stringset{}
		i        = storage.SeriesRef(0)
		series   = []seriesRepair{}
	)

	var builder labels.ScratchBuilder
	var chks []chunks.Meta
	for all.Next() {
		id := all.At()

		if err := indexr.Series(id, &builder, &chks); err != nil {
			return errors.Wrap(err, "series")
		}
		// Make sure labels are in sorted order.
		builder.Sort()

		for i, c := range chks {
			// Ignore iterable as it should be nil.
			chks[i].Chunk, _, err = chunkr.ChunkOrIterable(c)
			if err != nil {
				return errors.Wrap(err, "chunk read")
			}
		}

		chks, err := sanitizeChunkSequence(chks, meta.MinTime, meta.MaxTime, ignoreChkFns)
		if err != nil {
			return err
		}

		if len(chks) == 0 {

View on GitHub (pinned to 35b8b99117)