thanos-io/thanos · error

postings entries must be in increasing order, current

Error message

postings entries must be in increasing order, current: %d, previous: %d

What it means

The diff+varint encoding stores deltas between consecutive series refs, so postings MUST arrive in strictly increasing order. The encoder returns this error when a posting value is lower than the previous one, because a negative delta cannot be uvarint-encoded.

Solutions

  1. Fix the source of the unordered postings (usually corrupted index data)
  2. Run tsdb recovery / delete and rebuild affected block index files
  3. If implementing a custom Postings type, sort refs before iteration

Example fix

// before: custom Postings emitting unordered refs
refs := []uint64{5, 3, 9}
// after: sort before returning
sort.Slice(refs, func(i, j int) bool { return refs[i] < refs[j] })
Defensive patterns

Strategy: validation

Validate before calling

func postingsAreSorted(p index.Postings) (bool, error) {
    prev := storage.SeriesRef(0)
    for p.Next() {
        v := p.At()
        if v < prev { return false, nil }
        prev = v
    }
    return p.Err() == nil, p.Err()
}

Try / catch

b, err := diffVarintSnappyStreamedEncode(p, length)
if err != nil {
    if strings.Contains(err.Error(), "must be in increasing order") {
        return nil, fmt.Errorf("corrupt postings list: %w", err)
    }
    return nil, err
}

Prevention

When it happens

Trigger: encodePostingsToCache -> diffVarintSnappyStreamedEncode when p.At() returns a value < prev: an index.Postings iterator yielding out-of-order series refs.

Common situations: Corrupted index postings lists on disk; custom/buggy Postings implementations returning unordered refs; data race in the posting list construction.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at pkg/store/postings_codec.go:112

	compressedBuf := bytes.NewBuffer(make([]byte, 0, estimateSnappyStreamSize(length)))
	if n, err := compressedBuf.WriteString(codecHeaderStreamedSnappy); err != nil {
		return nil, fmt.Errorf("writing streamed snappy header")
	} else if n != len(codecHeaderStreamedSnappy) {
		return nil, fmt.Errorf("short-write streamed snappy header")
	}

	uvarintEncodeBuf := make([]byte, binary.MaxVarintLen64)

	sw, err := extsnappy.Compressor.Compress(compressedBuf)
	if err != nil {
		return nil, fmt.Errorf("creating snappy compressor: %w", err)
	}

	prev := storage.SeriesRef(0)
	for p.Next() {
		v := p.At()
		if v < prev {
			return nil, errors.Errorf("postings entries must be in increasing order, current: %d, previous: %d", v, prev)
		}

		uvarintSize := binary.PutUvarint(uvarintEncodeBuf, uint64(v-prev))
		if written, err := sw.Write(uvarintEncodeBuf[:uvarintSize]); err != nil {
			return nil, errors.Wrap(err, "writing uvarint encoded byte")
		} else if written != uvarintSize {
			return nil, errors.Wrap(err, "short-write for uvarint encoded byte")
		}

		prev = v
	}
	if p.Err() != nil {
		return nil, p.Err()
	}
	if err := sw.Close(); err != nil {
		return nil, errors.Wrap(err, "closing snappy stream writer")
	}

View on GitHub (pinned to 35b8b99117)