dgraph-io/badger · critical

initIndex crashed: %v %s

Error message

initIndex crashed: %v
%s

What it means

This message is produced by a deferred recover() handler in Table.initIndex. When opening a table (SST) file panics — typically because the mmap-slice t.Data contains zeros from a truncated, partially-synced, or botched file copy — initIndex converts the panic into this error, appending captured debug buffer contents for diagnosis.

Source

Thrown at table/table.go:349

		return nil, err
	}
	return t, nil
}

func (t *Table) initBiggestAndSmallest() (err error) {
	// This defer will help gathering debugging info in case initIndex crashes.
	defer func() {
		if r := recover(); r != nil {
			var debugBuf bytes.Buffer

			// Best-effort debug collection: a panic here must not escape and
			// re-trigger the fatalpanic we are trying to fix. Setting err inside
			// this defer (rather than after the reads below) ensures whatever
			// debug info was gathered so far is attached even if one of the
			// reads panics.
			defer func() {
				_ = recover()
				err = fmt.Errorf("initIndex crashed: %v\n%s", r, debugBuf.String())
			}()

			// Get the count of null bytes at the end of file. This is to make sure if there was an
			// issue with mmap sync or file copy.
			count := 0
			for i := len(t.Data) - 1; i >= 0; i-- {
				if t.Data[i] != 0 {
					break
				}
				count++
			}

			fmt.Fprintf(&debugBuf, "\n== Recovering from initIndex crash ==\n")
			fmt.Fprintf(&debugBuf, "File Info: [ID: %d, Size: %d, Zeros: %d]\n",
				t.id, t.tableSize, count)

			fmt.Fprintf(&debugBuf, "isEnrypted: %v ", t.shouldDecrypt())

View on GitHub (pinned to 2a001d466f)

Solutions

  1. Inspect the debug buffer text after 'crashed:' to identify the exact panic cause
  2. Delete or move the corrupted table file out of the data directory and reopen the DB
  3. Re-restore the data directory from a verified backup
  4. Check for filesystem/disk issues and verify file sizes match the manifest
  5. Never copy the data directory while the database is running; use DB.Backup/Stream instead

Example fix

// before: manually copying live SST files
cp -r /data/badger /backup/badger

// after: use a consistent snapshot
opt := badger.DefaultOptions("/data/badger").WithReadOnly(true)
db, _ := badger.Open(opt)
defer db.Close()
db.Backup(w, 0) // consistent backup instead of raw file copy
Defensive patterns

Strategy: validation

Validate before calling

info, err := os.Stat(tablePath)
if err != nil || info.Size() == 0 {
    return fmt.Errorf("table %s is empty/truncated", tablePath)
}
// stop Badger before copying directories; prefer db.Backup over file copies

Prevention

When it happens

Trigger: Calling db.Open (or badger.Open) where loading a table file panics inside initIndex; t.Data ends in null bytes because mmap sync failed, the file was copied while being written, or the file was truncated and re-extended with zeros.

Common situations: Copying SST files between machines without stopping Badger; crash/power-loss during mmap sync; restoring data directory from a partial backup; disk full during flush causing zero-padded files.

Related errors


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