dgraph-io/badger · critical

invalid table size in footer. Data corrupted

Error message

invalid table size in footer. Data corrupted

What it means

initIndex reads the table footer starting from the end of the file: the last 4 bytes hold the checksum length. If the table is smaller than 4 bytes, there is no valid footer, so Badger declares the data corrupted.

Source

Thrown at table/table.go:432

func (t *Table) read(off, sz int) ([]byte, error) {
	return t.Bytes(off, sz)
}

func (t *Table) readNoFail(off, sz int) []byte {
	res, err := t.read(off, sz)
	y.Check(err)
	return res
}

// initIndex reads the index and populate the necessary table fields and returns
// first block offset
func (t *Table) initIndex() (*fb.BlockOffset, error) {
	readPos := t.tableSize

	// Read checksum len from the last 4 bytes.
	if readPos < 4 {
		return nil, errors.New("invalid table size in footer. Data corrupted")
	}
	readPos -= 4
	buf := t.readNoFail(readPos, 4)
	checksumLen := int(y.BytesToU32(buf))
	// checksumLen == 0 is legal (a zero checksum marshals to nothing), so only
	// reject negative lengths and lengths that don't fit in the bytes remaining
	// before readPos. The < 0 guard catches a uint32 value >= 2^31 wrapping to a
	// negative int on 32-bit platforms.
	if checksumLen < 0 || checksumLen > readPos {
		return nil, errors.New("invalid checksum length in footer. Data corrupted")
	}

	// Read checksum.
	expectedChk := &pb.Checksum{}
	readPos -= checksumLen
	buf = t.readNoFail(readPos, checksumLen)
	if err := proto.Unmarshal(buf, expectedChk); err != nil {
		return nil, err

View on GitHub (pinned to 2a001d466f)

Solutions

  1. Check the file size with ls/stat; remove or quarantine zero/truncated SST files
  2. Restore the table file from a known-good backup
  3. Verify the data directory matches the MANIFEST (drop orphan files)
  4. Rebuild the database from an exported backup (db.Load from db.Backup output)

Example fix

// before: blindly opening every file in dir
// (badger hits the truncated 0-byte 000001.sst)

// after: verify before opening
info, err := os.Stat(path)
if err != nil || info.Size() < 4096 {
    os.Rename(path, path+".corrupt") // quarantine
}
Defensive patterns

Strategy: validation

Validate before calling

fi, err := os.Stat(path)
if err != nil || fi.Size() < 4096 { // minimal valid SST is far larger than 4 bytes
    os.Rename(path, path+".corrupt")
}

Prevention

When it happens

Trigger: Opening a table whose t.tableSize < 4 — a truncated, empty, or zero-length SST file passed to initIndex via initBiggestAndSmallest during DB open or table ingestion.

Common situations: Incomplete file copy; disk crash mid-write leaving a stub file; a stray non-SST file in the directory being picked up as a table; backup restore that skipped file contents.

Related errors


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