dgraph-io/badger · error

Cannot flatten in read-only mode.

Error message

Cannot flatten in read-only mode.

What it means

Returned by DB.Flatten when the database is in read-only mode. Flatten forces compactions across the LSM tree so all tables land on one level, and compaction writes new tables and rewrites the MANIFEST — operations that a read-only database cannot perform, hence the guard rejects the call.

Source

Thrown at db.go:1665

func (db *DB) startMemoryFlush() {
	// Start memory fluhser.
	if db.closers.memtable != nil {
		db.flushChan = make(chan *memTable, db.opt.NumMemtables)
		db.closers.memtable = z.NewCloser(1)
		go func() {
			db.flushMemtable(db.closers.memtable)
		}()
	}
}

// Flatten can be used to force compactions on the LSM tree so all the tables fall on the same
// level. This ensures that all the versions of keys are colocated and not split across multiple
// levels, which is necessary after a restore from backup. During Flatten, live compactions are
// stopped. Ideally, no writes are going on during Flatten. Otherwise, it would create competition
// between flattening the tree and new tables being created at level zero.
func (db *DB) Flatten(workers int) error {
	if db.opt.ReadOnly {
		panic("Cannot flatten in read-only mode.")
	}

	db.stopCompactions()
	defer db.startCompactions()

	compactAway := func(cp compactionPriority) error {
		db.opt.Infof("Attempting to compact with %+v\n", cp)
		errCh := make(chan error, 1)
		for i := 0; i < workers; i++ {
			go func() {
				errCh <- db.lc.doCompact(175, cp)
			}()
		}
		var success int
		var rerr error
		for i := 0; i < workers; i++ {
			err := <-errCh
			if err != nil {

View on GitHub (pinned to 2a001d466f)

Solutions

  1. Open the DB in write mode before calling Flatten
  2. Do Flatten on the primary/writable instance, not read-only replicas
  3. Check db.opt.ReadOnly before calling Flatten

Example fix

// before
opt.ReadOnly = true
db, _ := badger.Open(opt)
db.Flatten(4) // panics
// after
opt.ReadOnly = false // writable copy
db, _ := badger.Open(opt)
db.Flatten(4)
Defensive patterns

Strategy: validation

Validate before calling

if db.opt.ReadOnly { return errors.New("Flatten unavailable in read-only mode") }

Try / catch

defer func() {
    if r := recover(); r != nil {
        if strings.Contains(fmt.Sprint(r), "Cannot flatten in read-only") { /* schedule on writable node */ }
    }
}()

Prevention

When it happens

Trigger: Calling db.Flatten(workers) on a DB opened with badger.ReadOnly, typically after a restore or on a read-only replica.

Common situations: Running flatten/defrag maintenance scripts against a read-only mounted directory; read-only disaster-recovery nodes.

Related errors


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