{"record":{"id":"3a5d5410d9526596","repo":"dgraph-io/badger","slug":"unable-to-do-incremental-writes-because-memtable-h","errorCode":null,"errorMessage":"Unable to do incremental writes because MemTable has data","messagePattern":"Unable to do incremental writes because MemTable has data","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"stream_writer.go","lineNumber":100,"sourceCode":"\t// Before we start writing, we'll stop the compactions because no one else should be writing to\n\t// the same level as the stream writer is writing to.\n\tf, err := sw.db.prepareToDrop()\n\tif err != nil {\n\t\tsw.done = func() { once.Do(f) }\n\t\treturn err\n\t}\n\tsw.db.stopCompactions()\n\tdone := func() {\n\t\tsw.db.startCompactions()\n\t\tf()\n\t}\n\tsw.done = func() { once.Do(done) }\n\n\tmts, decr := sw.db.getMemTables()\n\tdefer decr()\n\tfor _, m := range mts {\n\t\tif !m.sl.Empty() {\n\t\t\treturn fmt.Errorf(\"Unable to do incremental writes because MemTable has data\")\n\t\t}\n\t}\n\n\tisEmptyDB := true\n\tfor _, level := range sw.db.Levels() {\n\t\tif level.NumTables > 0 {\n\t\t\tsw.prevLevel = level.Level\n\t\t\tisEmptyDB = false\n\t\t\tbreak\n\t\t}\n\t}\n\tif isEmptyDB {\n\t\t// If DB is empty, we should allow doing incremental stream write.\n\t\treturn nil\n\t}\n\tif sw.prevLevel == 0 {\n\t\t// It seems that data is present in all levels from Lmax to L0. If we call flatten\n\t\t// on the tree, all the data will go to Lmax. All the levels above will be empty","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/dgraph-io/badger/blob/2a001d466f6b71a917319a1db41f99860e16e269/stream_writer.go#L82-L118","documentation":"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.","triggerScenarios":"Calling StreamWriter.PrepareIncremental() while memtables are non-empty — i.e., writes/commits happened shortly before and were not flushed, or flushes were blocked.","commonSituations":"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.","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()"],"exampleFix":"// before\nsw := db.NewStreamWriter()\nerr := sw.PrepareIncremental() // fails: memtable has data\n// after\nsw := db.NewStreamWriter()\nif err := db.Flush(); err != nil { /* handle */ } // ensure memtables are empty\nerr := sw.PrepareIncremental()","handlingStrategy":"validation","validationCode":"// PrepareIncremental is only valid when all memtables are empty.\nif err := db.Flush(); err != nil { return err } // ensures memtable data is flushed to LSM\nif db.IsClosed() { return errors.New(\"db closed\") }\nerr := sw.PrepareIncremental()\nif err != nil && strings.Contains(err.Error(), \"MemTable has data\") {\n    // quiesce writes and flush, then retry\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["badger","streamwriter","incremental-write","memtable"],"backgroundTag":"memtable-not-flushed","analyzedSha":"2a001d466f6b71a917319a1db41f99860e16e269","analyzedAt":"2026-09-05T13:00:02.264Z","contentChangedAt":"2026-09-05T13:00:02.264Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}