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
- Fix the source of the unordered postings (usually corrupted index data)
- Run tsdb recovery / delete and rebuild affected block index files
- 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
- Always construct postings lists from sorted refs (tsdb guarantees this)
- Validate custom index.Postings implementations emit strictly increasing refs
- Rebuild index files when corruption is detected instead of re-encoding
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)