dgraph-io/badger · error

ErrDBClosed

ErrDBClosed

Error message

DB Closed

What it means

ErrDBClosed is a sentinel error returned when a data operation is attempted after DB.Close() has completed. DB.get (db.go:791) returns it whenever db.IsClosed() is true, and the iterator code panics with it (iterator.go:464) if an iterator is used after close. The public View/Update transaction helpers surface it to callers of Get/Iterate after shutdown.

Source

Thrown at errors.go:116

	// ErrEncryptionKeyMismatch is returned when the storage key is not
	// matched with the key previously given.
	ErrEncryptionKeyMismatch = stderrors.New("Encryption key mismatch")

	// ErrInvalidDataKeyID is returned if the datakey id is invalid.
	ErrInvalidDataKeyID = stderrors.New("Invalid datakey id")

	// ErrInvalidEncryptionKey is returned if length of encryption keys is invalid.
	ErrInvalidEncryptionKey = stderrors.New("Encryption key's length should be" +
		"either 16, 24, or 32 bytes")
	// ErrGCInMemoryMode is returned when db.RunValueLogGC is called in in-memory mode.
	ErrGCInMemoryMode = stderrors.New("Cannot run value log GC when DB is opened in InMemory mode")

	// ErrGCInReadOnlyMode is returned when db.RunValueLogGC is called in read-only mode.
	ErrGCInReadOnlyMode = stderrors.New("Cannot run value log GC when DB is opened in ReadOnly mode")

	// ErrDBClosed is returned when a get operation is performed after closing the DB.
	ErrDBClosed = stderrors.New("DB Closed")
)

View on GitHub (pinned to 2a001d466f)

Solutions

  1. Ensure Close() is the last operation: cancel/clean up all goroutines, wait for in-flight requests (WaitGroup), then close.
  2. Guard every access with db.IsClosed() before View/Update, or track closed state in application code.
  3. Use errors.Is(err, badger.ErrDBClosed) to distinguish shutdown races from real failures and fail gracefully.
  4. Fix double-close ordering bugs: never issue reads after a deferred Close in the same call path.

Example fix

// before
go refreshCache(db)
db.Close()
// after
var wg sync.WaitGroup
wg.Add(1)
go func() { defer wg.Done(); refreshCache(db) }()
wg.Wait()
db.Close()
// and in read paths:
if db.IsClosed() { return badger.ErrDBClosed }
Defensive patterns

Strategy: try-catch

Validate before calling

if db.IsClosed() {
    return badger.ErrDBClosed // or skip the read
}
err := db.View(func(txn *badger.Txn) error { ... })

Type guard

func (w *SafeDB) usable() bool {
    w.mu.RLock()
    defer w.mu.RUnlock()
    return !w.db.IsClosed()
}

Try / catch

err := db.View(func(txn *badger.Txn) error { ... })
if errors.Is(err, badger.ErrDBClosed) {
    // DB is shutting down: log, drop the request or return a clean shutdown code
    return nil
}

Prevention

When it happens

Trigger: Calling db.View(), db.Update(), txn.Get() or creating/using an iterator after db.Close() has returned; also background goroutines or deferred callbacks that outlive Close and keep touching the DB.

Common situations: Application shutdown racing with in-flight request handlers; background cache-refresh goroutines not cancelled before Close; accidental double-close followed by a read; tests calling View after Close.

Related errors


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