From dcda4840a70ac6f3f29c82b0e7947c4586537a41 Mon Sep 17 00:00:00 2001 From: Patryk Prus Date: Tue, 6 Jan 2026 08:07:23 -0500 Subject: [PATCH] tsdb/index: export sentinel errors for size limit failures (#17773) * tsdb/index: export sentinel errors for size limit failures --------- Signed-off-by: Patryk Prus Co-authored-by: Arve Knudsen --- tsdb/index/index.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tsdb/index/index.go b/tsdb/index/index.go index 1ddcac9501..8a76770821 100644 --- a/tsdb/index/index.go +++ b/tsdb/index/index.go @@ -17,6 +17,7 @@ import ( "bufio" "context" "encoding/binary" + "errors" "fmt" "hash" "hash/crc32" @@ -94,6 +95,13 @@ func (s indexWriterStage) String() string { return "" } +// ErrPostingsOffsetTableTooLarge is returned when the postings offset table length +// would exceed 4 bytes (table would exceed the 4GB limit). +var ErrPostingsOffsetTableTooLarge = errors.New("length size exceeds 4 bytes") + +// ErrIndexExceeds64GiB is returned when the index file would exceed the 64GiB limit. +var ErrIndexExceeds64GiB = errors.New("exceeding max size of 64GiB") + // The table gets initialized with sync.Once but may still cause a race // with any other use of the crc32 package anywhere. Thus we initialize it // before. @@ -303,7 +311,7 @@ func (fw *FileWriter) Write(bufs ...[]byte) error { // Once we move to compressed/varint representations in those areas, this limitation // can be lifted. if fw.pos > 16*math.MaxUint32 { - return fmt.Errorf("%q exceeding max size of 64GiB", fw.name) + return fmt.Errorf("%q %w", fw.name, ErrIndexExceeds64GiB) } } return nil @@ -660,7 +668,7 @@ func (w *Writer) writeLengthAndHash(startPos uint64) error { w.buf1.Reset() l := w.f.pos - startPos - 4 if l > math.MaxUint32 { - return fmt.Errorf("length size exceeds 4 bytes: %d", l) + return fmt.Errorf("%w: %d", ErrPostingsOffsetTableTooLarge, l) } w.buf1.PutBE32int(int(l)) if err := w.writeAt(w.buf1.Get(), startPos); err != nil {