dgraph-io/badger · error

there is a non-empty level %d above base level %d

Error message

there is a non-empty level %d above base level %d

What it means

When compacting from L0 to the base level, runCompactDef verifies no intermediate level between 0 and the base level contains data; if a non-empty level sits above the computed base level, proceeding would break LSM invariants, so it returns this error.

Source

Thrown at levels.go:1492

			continue
		}
		if !s.cstatus.compareAndAdd(thisAndNextLevelRLocked{}, *cd) {
			continue
		}
		return true
	}
	return false
}

func (s *levelsController) runCompactDef(id, l int, cd compactDef) (err error) {
	if len(cd.t.fileSz) == 0 {
		return errors.New("Filesizes cannot be zero. Targets are not set")
	}

	if cd.thisLevel.level == 0 {
		for i := cd.nextLevel.level - 1; i > 0; i-- {
			if s.levels[i].getTotalSize() > 0 {
				return fmt.Errorf("there is a non-empty level %d above base level %d", i, cd.nextLevel.level)
			}
		}
	}

	timeStart := time.Now()

	thisLevel := cd.thisLevel
	nextLevel := cd.nextLevel

	y.AssertTrue(len(cd.splits) == 0)
	if thisLevel.level == nextLevel.level {
		// don't do anything for L0 -> L0 and Lmax -> Lmax.
	} else {
		s.addSplits(&cd)
	}
	if len(cd.splits) == 0 {
		cd.splits = append(cd.splits, keyRange{})
	}

View on GitHub (pinned to 2a001d466f)

Solutions

  1. Recompute baseLevel via the controller (refreshPriorPriorLevel / levelTargets) before running the compaction
  2. Don't force L0->Lbase compactions with hand-built priorities; let automatic compaction pick correct base levels
  3. Reopen the DB so the levels controller re-scans levels if state seems stale

Example fix

// before
db.lc.doCompact(173, compactionPriority{level: 0, score: 1.73, baseLevel: 1}) // stale baseLevel=1 while L1 non-empty
// after
db.lc.startCompact() // let the controller schedule with a freshly computed baseLevel
Defensive patterns

Strategy: retry

Validate before calling

// Go: verify intermediate levels are empty before forcing an L0 compaction
for i := 1; i < cd.nextLevel.level; i++ {
    if s.levels[i].getTotalSize() > 0 { return fmt.Errorf("level %d non-empty", i) }
}

Try / catch

// Go
if err := s.runCompactDef(id, 0, cd); err != nil {
    if strings.Contains(err.Error(), "non-empty level") {
        time.Sleep(100 * time.Millisecond) // recompute and retry once
        return s.doCompact(id, s.pickPriority())
    }
    return err
}

Prevention

When it happens

Trigger: A compaction definition with thisLevel == 0 and nextLevel (base) such that some level i in (0, nextLevel) has getTotalSize() > 0 — i.e., baseLevel computed incorrectly or levels populated between scheduling and execution.

Common situations: Manually induced L0 compactions with a stale/incorrect baseLevel; concurrent activity changing level contents between schedule and run; option changes (MaxLevels/size targets) shifting base-level computation mid-flight.

Related errors


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