dgraph-io/badger · critical

invalid checksum length in footer. Data corrupted

Error message

invalid checksum length in footer. Data corrupted

What it means

After reading checksumLen from the footer's last 4 bytes, initIndex validates it: a negative value (uint32 >= 2^31 wrapped on 32-bit platforms) or a value larger than the bytes remaining before the footer position means the footer is garbage, so the table is rejected as corrupted.

Source

Thrown at table/table.go:442

// 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
	}

	// Read index size from the footer.
	if readPos < 4 {
		return nil, errors.New("invalid table size in footer. Data corrupted")
	}
	readPos -= 4
	buf = t.readNoFail(readPos, 4)
	t.indexLen = int(y.BytesToU32(buf))
	// A table always has at least one block, so a zero indexLen is always

View on GitHub (pinned to 2a001d466f)

Solutions

  1. Verify the file wasn't produced by a different Badger/LSM format version
  2. Re-transfer the file and compare checksums (md5sum) with the source
  3. Quarantine the corrupt table file and restore from backup
  4. Rebuild the DB via db.Load(db.Backup output) onto a fresh directory

Example fix

// before: mixing sst files from badger v2 dir into v3 data dir

// after: migrate via export/import
db.Backup(w, 0)        // from old version DB
newdb.Load(r, 0)       // into fresh v3 directory
Defensive patterns

Strategy: validation

Validate before calling

if len(data) < 4 {
    return errors.New("file too small to contain a footer")
}
chkLen := binary.LittleEndian.Uint32(data[len(data)-4:])
if int(chkLen) > len(data)-4 {
    return errors.New("footer checksum length implausible — corrupt or wrong version")
}

Prevention

When it happens

Trigger: Opening a table whose last 4 bytes decode to an absurd checksum length — the file was written by a different/incompatible format version, was corrupted in transit, or its tail was overwritten.

Common situations: Mixing SST files across incompatible Badger versions; rsync/ftp in ASCII mode or with corruption; tail-sector disk damage; editing or truncating SST files manually.

Related errors


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