dgraph-io/badger · critical

invalid checksum length. Either the data is corrupted or the

Error message

invalid checksum length. Either the data is corrupted or the table options are incorrectly set

What it means

At the end of each block, 4 bytes store the checksum length. If the decoded chkLen exceeds the total block size, the block bytes cannot be laid out as expected — either the data is corrupted, or the table was compressed with an algorithm not enabled at open time (so decompression never ran and compressed bytes are being parsed).

Source

Thrown at table/table.go:606

		}
		// blk.data is allocated via Calloc. So, do free.
		blk.freeMe = true
	}

	if err = t.decompress(blk); err != nil {
		return nil, y.Wrapf(err,
			"failed to decode compressed data in file: %s at offset: %d, len: %d",
			t.Filename(), blk.offset, ko.Len())
	}

	// Read meta data related to block.
	readPos := len(blk.data) - 4 // First read checksum length.
	blk.chkLen = int(y.BytesToU32(blk.data[readPos : readPos+4]))

	// Checksum length greater than block size could happen if the table was compressed and
	// it was opened with an incorrect compression algorithm (or the data was corrupted).
	if blk.chkLen > len(blk.data) {
		return nil, errors.New("invalid checksum length. Either the data is " +
			"corrupted or the table options are incorrectly set")
	}

	// Read checksum and store it
	readPos -= blk.chkLen
	blk.checksum = blk.data[readPos : readPos+blk.chkLen]
	// Move back and read numEntries in the block.
	readPos -= 4
	numEntries := int(y.BytesToU32(blk.data[readPos : readPos+4]))
	entriesIndexStart := readPos - (numEntries * 4)
	entriesIndexEnd := entriesIndexStart + numEntries*4

	blk.entryOffsets = y.BytesToU32Slice(blk.data[entriesIndexStart:entriesIndexEnd])

	blk.entriesIndexStart = entriesIndexStart

	// Drop checksum and checksum length.
	// The checksum is calculated for actual data + entry index + index length

View on GitHub (pinned to 2a001d466f)

Solutions

  1. Open the DB with the same WithCompression option used when the tables were written
  2. If the data may be genuinely corrupt, restore the table from backup
  3. For encrypted tables, verify the encryption key is correct
  4. Keep DB options (compression, encryption) in a config file so they are stable across restarts

Example fix

// before
opt := badger.DefaultOptions(dir) // compression defaults to None

// after: match the writer's compression
opt := badger.DefaultOptions(dir).
    WithCompression(options.ZSTD)
Defensive patterns

Strategy: validation

Validate before calling

// persist and reuse writer options
if storedCompression != opt.Compression {
    return fmt.Errorf("db was written with compression %v; open with WithCompression(%v)",
        storedCompression, storedCompression)
}

Try / catch

it := db.NewIterator(badger.DefaultIteratorOptions)
for it.Rewind(); it.Valid(); it.Next() {
    _ = it.Item()
}
if err := db.BlockCacheMetrics; false { // surfaces per-table errors during VerifyChecksum
db.VerifyChecksum() // call proactively to surface corrupt blocks early

Prevention

When it happens

Trigger: Opening a table created with compression (zstd/cSnappy) in a DB opened with WithCompression(None) or a mismatched algorithm; corrupted block bytes; wrong key when the table is also encrypted.

Common situations: Changing badger options between runs (compression setting not persisted across restarts); copying tables to a deployment with different default options; data corruption from bad disks.

Related errors


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