thanos-io/thanos · error
new TOC
Error message
new TOC
What it means
The TOC bytes were fetched and the reader closed, but index.NewTOCFromByteSlice failed while parsing the TOC structure (or validating its CRC32). This means the final bytes of the index file are not a well-formed table of contents, so the index-header cannot be built.
Solutions
- Verify the index object size matches attrs.Size and re-upload the block if the object is truncated.
- Delete the corrupt block (or remove it from the bucket) so store/gateway stops loading it; restore from a replica.
- If size mismatch came from cached metadata, invalidate the cached attributes and re-fetch.
- Run a block integrity check (e.g. thanos tools bucket verify) to identify and quarantine corrupt blocks.
Defensive patterns
Strategy: validation
Validate before calling
attrs, _ := bkt.Attributes(ctx, path)
if attrs.Size < int64(indexTOCLen+crc32.Size) {
return fmt.Errorf("index %s truncated: %d bytes", path, attrs.Size)
} Prevention
- Run periodic bucket verification (thanos tools bucket verify) and quarantine failing blocks.
- Ensure block uploads verify size/CRC after transfer.
- Restore blocks from replicas before deleting corrupt originals.
- Keep block attrs fresh; avoid building headers against stale metadata.
When it happens
Trigger: newChunkedIndexReader -> readTOC when NewTOCFromByteSlice rejects the tocBytes: wrong TOC offset (r.size from attrs does not match the actual object), truncated index object, or a structurally invalid TOC written by a broken writer.
Common situations: Index object truncated mid-upload so the TOC tail is missing; stale attrs.Size after the object was replaced with a different-sized one; blocks corrupted during copy between buckets; CRC mismatch from bit rot.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/91cbdd74b1392c1f.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/block/indexheader/binary_reader.go:247
func (r *chunkedIndexReader) readTOC() (*index.TOC, error) {
rc, err := r.bkt.GetRange(r.ctx, r.path, int64(r.size-indexTOCLen-crc32.Size), indexTOCLen+crc32.Size)
if err != nil {
return nil, errors.Wrapf(err, "get TOC from object storage of %s", r.path)
}
tocBytes, err := io.ReadAll(rc)
if err != nil {
runutil.CloseWithErrCapture(&err, rc, "close toc reader")
return nil, errors.Wrapf(err, "get TOC from object storage of %s", r.path)
}
if err := rc.Close(); err != nil {
return nil, errors.Wrap(err, "close toc reader")
}
toc, err := index.NewTOCFromByteSlice(realByteSlice(tocBytes))
if err != nil {
return nil, errors.Wrap(err, "new TOC")
}
return toc, nil
}
func (r *chunkedIndexReader) CopySymbols(w io.Writer, buf []byte) (err error) {
rc, err := r.bkt.GetRange(r.ctx, r.path, int64(r.toc.Symbols), int64(r.toc.Series-r.toc.Symbols))
if err != nil {
return errors.Wrapf(err, "get symbols from object storage of %s", r.path)
}
defer runutil.CloseWithErrCapture(&err, rc, "close symbol reader")
if _, err := io.CopyBuffer(w, rc, buf); err != nil {
return errors.Wrap(err, "copy symbols")
}
return nil
}
View on GitHub (pinned to 35b8b99117)