dgraph-io/badger · error
Unable to do incremental writes because MemTable has data
Error message
Unable to do incremental writes because MemTable has data
What it means
PrepareIncremental requires the DB to have all data flushed out of memtables so that the incremental StreamWriter can exclusively own the LSM levels. If any memtable still holds data, the library returns this error instead of producing a corrupted incremental snapshot.
Source
Thrown at stream_writer.go:100
// Before we start writing, we'll stop the compactions because no one else should be writing to
// the same level as the stream writer is writing to.
f, err := sw.db.prepareToDrop()
if err != nil {
sw.done = func() { once.Do(f) }
return err
}
sw.db.stopCompactions()
done := func() {
sw.db.startCompactions()
f()
}
sw.done = func() { once.Do(done) }
mts, decr := sw.db.getMemTables()
defer decr()
for _, m := range mts {
if !m.sl.Empty() {
return fmt.Errorf("Unable to do incremental writes because MemTable has data")
}
}
isEmptyDB := true
for _, level := range sw.db.Levels() {
if level.NumTables > 0 {
sw.prevLevel = level.Level
isEmptyDB = false
break
}
}
if isEmptyDB {
// If DB is empty, we should allow doing incremental stream write.
return nil
}
if sw.prevLevel == 0 {
// It seems that data is present in all levels from Lmax to L0. If we call flatten
// on the tree, all the data will go to Lmax. All the levels above will be emptyView on GitHub (pinned to 2a001d466f)
Solutions
- Flush memtables first: call db.Flush() (or db.Close + reopen) so all memtables are empty, then call PrepareIncremental()
- Pause/stop all writers and wait for pending transactions to commit before preparing the incremental writer
- If the DB is idle and data still lingers, tune WithMemTableSize lower or trigger a manual flush via db.Flush()
Example fix
// before
sw := db.NewStreamWriter()
err := sw.PrepareIncremental() // fails: memtable has data
// after
sw := db.NewStreamWriter()
if err := db.Flush(); err != nil { /* handle */ } // ensure memtables are empty
err := sw.PrepareIncremental() Defensive patterns
Strategy: validation
Validate before calling
// PrepareIncremental is only valid when all memtables are empty.
if err := db.Flush(); err != nil { return err } // ensures memtable data is flushed to LSM
if db.IsClosed() { return errors.New("db closed") }
err := sw.PrepareIncremental()
if err != nil && strings.Contains(err.Error(), "MemTable has data") {
// quiesce writes and flush, then retry
} Prevention
- Always call db.Flush() (and stop writers) before PrepareIncremental()
- Do not run incremental stream writers concurrently with active transaction commits on the same DB
- Check for the 'MemTable has data' string and retry once after a flush in idempotent pipelines
When it happens
Trigger: Calling StreamWriter.PrepareIncremental() while memtables are non-empty — i.e., writes/commits happened shortly before and were not flushed, or flushes were blocked.
Common situations: Running incremental stream backups on a live, write-heavy DB without forcing a flush first; integrating PrepareIncremental into a pipeline that does not quiesce writes.
Related errors
- error during flatten in StreamWriter: %w
- write performed on closed stream: %d
- File %s already exists
- while file.stat on file: %s, error: %v
- ErrValueLogSize
AI-assisted analysis of dgraph-io/badger@2a001d466f (2026-09-05).
Data as JSON: /api/errors/3a5d5410d9526596.
Report an issue: GitHub.