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, errView on GitHub (pinned to 2a001d466f)
Solutions
- Check the file size with ls/stat; remove or quarantine zero/truncated SST files
- Restore the table file from a known-good backup
- Verify the data directory matches the MANIFEST (drop orphan files)
- 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
- Verify copied file sizes/checksums after any directory transfer
- Keep the MANIFEST in sync with the table files; drop orphans
- Use filesystem-level snapshots (LVM/ZFS) rather than partial copies
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
- invalid checksum length in footer. Data corrupted
- invalid index length in footer. Data corrupted
- initIndex crashed: %v %s
- Unsupported compression type
- ErrValueLogSize
AI-assisted analysis of dgraph-io/badger@2a001d466f (2026-09-05).
Data as JSON: /api/errors/7d7919f92d1c1f73.
Report an issue: GitHub.