dgraph-io/badger · error

block out of index

Error message

block out of index

What it means

Table.block returns this error when the requested block index is >= the number of block offsets in the table index (negative is asserted separately). It means the caller asked for a block that does not exist in this table.

Source

Thrown at table/table.go:555

	}

	index, err := t.readTableIndex()
	y.Check(err)
	t.opt.IndexCache.Set(t.indexKey(), index, int64(t.indexLen))
	return index
}

func (t *Table) offsets(ko *fb.BlockOffset, i int) bool {
	return t.fetchIndex().Offsets(ko, i)
}

// block function return a new block. Each block holds a ref and the byte
// slice stored in the block will be reused when the ref becomes zero. The
// caller should release the block by calling block.decrRef() on it.
func (t *Table) block(idx int, useCache bool) (*Block, error) {
	y.AssertTruef(idx >= 0, "idx=%d", idx)
	if idx >= t.offsetsLength() {
		return nil, errors.New("block out of index")
	}
	if t.opt.BlockCache != nil {
		key := t.blockCacheKey(idx)
		blk, ok := t.opt.BlockCache.Get(key)
		if ok && blk != nil {
			// Use the block only if the increment was successful. The block
			// could get evicted from the cache between the Get() call and the
			// incrRef() call.
			if blk.incrRef() {
				return blk, nil
			}
		}
	}

	var ko fb.BlockOffset
	y.AssertTrue(t.offsets(&ko, idx))
	blk := &Block{offset: int(ko.Offset())}
	blk.ref.Store(1)

View on GitHub (pinned to 2a001d466f)

Solutions

  1. Guard the block index against offsetsLength() before calling t.block(idx, ...)
  2. Upgrade Badger — races between iteration and table dropping were fixed over time
  3. If it appears during open, treat the table as corrupt and restore it from backup
  4. Check that no custom code calls block() with hand-computed indices

Example fix

// before
blk, err := t.block(idx, true)

// after
if idx >= t.offsetsLength() {
    return io.EOF // or handle gracefully
}
blk, err := t.block(idx, true)
Defensive patterns

Strategy: type-guard

Type guard

func (t *table) hasBlock(idx int) bool {
    return idx >= 0 && idx < t.offsetsLength()
}
// call site: if !hasBlock(idx) { return io.EOF }

Try / catch

blk, err := tbl.block(idx, true)
if errors.Is(err, errBlockOutOfIndex) || err != nil && err.Error() == "block out of index" {
    return io.EOF // end iteration gracefully
}

Prevention

When it happens

Trigger: Iterator code (seekToFirst, seekToLast, seekHelper, next, prev) or VerifyChecksum computing a block index from offsets and running past the last block — usually due to a stale/corrupt index, concurrent table deletion, or an out-of-range idx from binary search over corrupted offsets.

Common situations: Corrupted index lengths from damaged SSTs; race between iterators and table cleanup (DropAll/compaction) in older versions; custom code indexing t.offsets() directly.

Related errors


AI-assisted analysis of dgraph-io/badger@2a001d466f (2026-09-05). Data as JSON: /api/errors/e293c2b5c6bf131b. Report an issue: GitHub.