dgraph-io/badger · critical

Base level can't be zero.

Error message

Base level can't be zero.

What it means

fillTablesL0ToLbase panics if the compaction's next level is 0; L0->Lbase compaction must target a base level above 0. Reaching this panic indicates an internal invariant violation in level-controller state (baseLevel computation went wrong), often due to corrupted options or manifest state.

Source

Thrown at levels.go:1256

	cd.thisRange = infRange
	cd.top = out

	// Avoid any other L0 -> Lbase from happening, while this is going on.
	thisLevel := s.cstatus.levels[cd.thisLevel.level]
	thisLevel.ranges = append(thisLevel.ranges, infRange)
	for _, t := range out {
		s.cstatus.tables[t.ID()] = struct{}{}
	}

	// For L0->L0 compaction, we set the target file size to max, so the output is always one file.
	// This significantly decreases the L0 table stalls and improves the performance.
	cd.t.fileSz[0] = math.MaxUint32
	return true
}

func (s *levelsController) fillTablesL0ToLbase(cd *compactDef) bool {
	if cd.nextLevel.level == 0 {
		panic("Base level can't be zero.")
	}
	// We keep cd.p.adjusted > 0.0 here to allow functions in db.go to artificially trigger
	// L0->Lbase compactions. Those functions wouldn't be setting the adjusted score.
	if cd.p.adjusted > 0.0 && cd.p.adjusted < 1.0 {
		// Do not compact to Lbase if adjusted score is less than 1.0.
		return false
	}
	cd.lockLevels()
	defer cd.unlockLevels()

	top := cd.thisLevel.tables
	if len(top) == 0 {
		return false
	}

	var out []*table.Table
	if len(cd.dropPrefixes) > 0 {
		// Use all tables if drop prefix is set. We don't want to compact only a

View on GitHub (pinned to 2a001d466f)

Solutions

  1. Do not call internal doCompact/fillTablesL0ToLbase directly with hand-built compactionPriority structs
  2. Verify MaxLevels and level size options are sane so baseLevel > 0 is computed
  3. Update badger to a version with the level-controller fixes if the panic occurs during normal operation

Example fix

// before
db.lc.doCompact(173, compactionPriority{level: 0, score: 1.73}) // baseLevel unset -> 0 -> panic
// after
db.lc.doCompact(173, compactionPriority{level: 0, score: 1.73, t: db.lc.levelTargets(), baseLevel: 1}) // ensure baseLevel >= 1
Defensive patterns

Strategy: fallback

Validate before calling

// Go: only trigger compactions through public APIs
// use db.RunValueLogGC / automatic compaction instead of db.lc.doCompact(...)

Try / catch

// Go
func triggerCompact(db *badger.DB) (err error) {
    defer func() { if r := recover(); r != nil { err = fmt.Errorf("compaction panic: %v", r) } }()
    return db.Flatten(2) // safe public alternative
}

Prevention

When it happens

Trigger: Internal compaction scheduling computing nextLevel == 0 for an L0 compaction; induced compactions (like doCompact with a hand-made compactionPriority) where baseLevel wasn't set; MaxLevels/level-target options resulting in a zero base level.

Common situations: Custom code calling db.lc.doCompact or starting compactions with malformed compactionPriority; corrupted level-controller state after option changes (e.g. NumLevelZeroTables thresholds, MaxLevels).

Related errors


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