thanos-io/thanos · error

get postings offset entry

Error message

get postings offset entry

What it means

Wrapped decoder error from PostingsOffset: while iterating the postings offset table via index.Decoder to find ranges for a name/value pair, the decoder reported d.Err() (malformed uvarint data or unexpected EOF).

Solutions

  1. Rebuild the index-header file (delete from bucket, let Thanos regenerate)
  2. Verify the block index integrity and re-upload/re-compact if corrupted
  3. Restore the block from a backup if storage corruption is confirmed
Defensive patterns

Strategy: try-catch

Try / catch

rngs, err := br.PostingsOffset(name, value); if err != nil && strings.Contains(err.Error(), "get postings offset entry") { fall back to full index postings reader or rebuild header }

Prevention

When it happens

Trigger: Calling Reader.PostingsOffset(name, value) when the sampled postings table bytes are corrupt/truncated so the decode loop hits a decoding error before finding or exhausting entries.

Common situations: Corrupt index files in storage; index-header built from an index that later changed; bit rot or partial transfer of block data.

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/0d567c4d508b2356. Report an issue: GitHub.

Appendix: source

Thrown at pkg/block/indexheader/binary_reader.go:977

			// Let's exit and do binary search again / exit if nothing wanted.

			if len(newSameRngs) > 0 {
				// We added some ranges in this iteration. Use next posting offset as the end of our ranges.
				// We know it exists as we never go further in this loop than e.offsets[i, i+1).

				skipNAndName(&d, &buf)
				d.UvarintBytes() // Label value.
				postingOffset := int64(d.Uvarint64())

				for j := range newSameRngs {
					newSameRngs[j].End = postingOffset - crc32.Size
				}
				rngs = append(rngs, newSameRngs...)
			}
			break
		}
		if d.Err() != nil {
			return nil, errors.Wrap(d.Err(), "get postings offset entry")
		}
	}

	return rngs, nil
}

func (r *BinaryReader) LookupSymbol(ctx context.Context, o uint32) (string, error) {
	if r.indexVersion == index.FormatV1 {
		// For v1 little trick is needed. Refs are actual offset inside index, not index-header. This is different
		// of the header length difference between two files.
		o += headerLen - index.HeaderLen
	}

	if s, ok := r.nameSymbols[o]; ok {
		return s, nil
	}

	cacheIndex := o % valueSymbolsCacheSize

View on GitHub (pinned to 35b8b99117)