dgraph-io/badger · error

Index Cache must be set for encrypted workloads

Error message

Index Cache must be set for encrypted workloads

What it means

For encrypted workloads the table index cannot be kept as plain bytes in memory; it must be cached decrypted. fetchIndex panics when the table requires decryption but opt.IndexCache is nil, because there would be nowhere to store the decrypted index.

Source

Thrown at table/table.go:533

	for i := 0; i < oLen; i += jump {
		if i >= oLen {
			i = oLen - 1
		}
		y.AssertTrue(t.offsets(&bo, i))
		if bytes.HasPrefix(bo.KeyBytes(), prefix) {
			res = append(res, string(bo.KeyBytes()))
		}
	}
	return res
}

func (t *Table) fetchIndex() *fb.TableIndex {
	if !t.shouldDecrypt() {
		return t._index
	}

	if t.opt.IndexCache == nil {
		panic("Index Cache must be set for encrypted workloads")
	}
	if val, ok := t.opt.IndexCache.Get(t.indexKey()); ok && val != nil {
		return val
	}

	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.

View on GitHub (pinned to 2a001d466f)

Solutions

  1. Set WithIndexCache (e.g. ristretto.NewCache) in the options when encryption is enabled
  2. Re-open the DB with both WithEncryptionKey and a non-nil IndexCache
  3. If encryption is unintended, remove WithEncryptionKey so fetchIndex returns the plain index

Example fix

// before
opt := badger.DefaultOptions(dir).
    WithEncryptionKey(key)

// after
ic, _ := ristretto.NewCache(&ristretto.Config{NumCounters: 1e6, MaxCost: 1 << 30})
opt := badger.DefaultOptions(dir).
    WithEncryptionKey(key).
    WithIndexCache(ic)
Defensive patterns

Strategy: validation

Validate before calling

if opt.EncryptionKey != nil && opt.IndexCache == nil {
    ic, err := ristretto.NewCache(&ristretto.Config{
        NumCounters: 1e6, MaxCost: 1 << 30, BufferItems: 64,
    })
    if err != nil { return err }
    opt.IndexCache = ic
}

Try / catch

func safeOpen(opt badger.Options) (*badger.DB, error) {
    if opt.EncryptionKey != nil && opt.IndexCache == nil {
        return nil, errors.New("encryption requires WithIndexCache")
    }
    return badger.Open(opt)
}

Prevention

When it happens

Trigger: Opening a DB with WithEncryptionKey set but without WithIndexCache, then calling any API that reads the index: t.offsets(), StaleDataSize(), DoesNotHave(), VerifyChecksum(), or normal iteration on an encrypted table.

Common situations: Users enabling Badger's encryption feature but forgetting the mandatory IndexCache option; copying options from a non-encrypted setup to an encrypted one.

Related errors


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