dgraph-io/badger · error
Block size cannot be zero
Error message
Block size cannot be zero
What it means
OpenTable requires a nonzero BlockSize whenever the table is compressed. BlockSize is used to size the decompression buffer for blocks, so a zero BlockSize with compression other than options.None makes block decoding impossible; OpenTable closes the mmap file and returns this error.
Source
Thrown at table/table.go:273
written := bd.Copy(mf.Data)
y.AssertTrue(written == len(mf.Data))
if err := z.Msync(mf.Data); err != nil {
return nil, y.Wrapf(err, "while calling msync on %s", fname)
}
return OpenTable(mf, *builder.opts)
}
// OpenTable assumes file has only one table and opens it. Takes ownership of fd upon function
// entry. Returns a table with one reference count on it (decrementing which may delete the file!
// -- consider t.Close() instead). The fd has to writeable because we call Truncate on it before
// deleting. Checksum for all blocks of table is verified based on value of chkMode.
func OpenTable(mf *z.MmapFile, opts Options) (*Table, error) {
// BlockSize is used to compute the approximate size of the decompressed
// block. It should not be zero if the table is compressed.
if opts.BlockSize == 0 && opts.Compression != options.None {
_ = mf.Close(-1)
return nil, errors.New("Block size cannot be zero")
}
fileInfo, err := mf.Fd.Stat()
if err != nil {
mf.Close(-1)
return nil, y.Wrap(err, "")
}
filename := fileInfo.Name()
id, ok := ParseFileID(filename)
if !ok {
mf.Close(-1)
return nil, fmt.Errorf("Invalid filename: %s", filename)
}
t := &Table{
MmapFile: mf,
id: id,
opt: &opts,
IsInmemory: false,View on GitHub (pinned to 2a001d466f)
Solutions
- Set opts.BlockSize to the same block size used when the table was built (default badger block size, e.g. 4KB) whenever opts.Compression != options.None
- Pass the table's original options rather than a zero-value Options{}; or set Compression to options.None if the table is truly uncompressed
- Use the DB-level open path (badger.Open) instead of calling OpenTable directly so correct options are loaded from the manifest
- If writing a test, mirror the writer's options: BlockSize = builder's block size
Example fix
// before
tbl, err := table.OpenTable(mf, table.Options{Compression: options.ZSTD}) // BlockSize 0
// after
tbl, err := table.OpenTable(mf, table.Options{Compression: options.ZSTD, BlockSize: 4096}) Defensive patterns
Strategy: validation
Validate before calling
if opts.Compression != options.None && opts.BlockSize == 0 {
return errors.New("BlockSize must be nonzero when compression is enabled")
} Type guard
func openTableOptsValid(o table.Options) bool {
return o.Compression == options.None || o.BlockSize > 0
} Try / catch
tbl, err := table.OpenTable(mf, opts)
if err != nil {
if err.Error() == "Block size cannot be zero" {
opts.BlockSize = 4096 // badger default
tbl, err = table.OpenTable(mf, opts)
}
if err != nil { return nil, err }
} Prevention
- When enabling Snappy/ZSTD, always set BlockSize alongside Compression
- Reuse the writer's options when opening tables (open via badger.Open, not raw OpenTable)
- Avoid zero-value Options{} for compressed tables
- Keep BlockSize identical between builder and reader options
When it happens
Trigger: Calling OpenTable with opts.Compression set to Snappy/ZSTD while opts.BlockSize is 0 (zero-value Options); reading an existing table with wrong OpenTable options where BlockSize wasn't propagated from the DB's stored options.
Common situations: Constructing table.Options by hand for a one-off table read and forgetting BlockSize; copying Options across Badger versions where the field was renamed or defaulted differently; tests opening tables with empty Options{} while the table was written with compression enabled.
Related errors
AI-assisted analysis of dgraph-io/badger@2a001d466f (2026-09-05).
Data as JSON: /api/errors/dcfa3ff20fa36d5b.
Report an issue: GitHub.