dgraph-io/badger · error

wb.err: %w err: %w

Error message

wb.err: %w err: %w

What it means

WriteBatch.Flush waits for all async batch commits to finish (via throttle.Finish) and then reports accumulated errors. If both the throttled commit returned an error AND earlier SetEntry calls already recorded an error in the batch, Flush wraps both with "wb.err: %w err: %w" so neither failure is lost.

Source

Thrown at batch.go:224

	return wb.Error()
}

// Flush must be called at the end to ensure that any pending writes get committed to Badger. Flush
// returns any error stored by WriteBatch.
func (wb *WriteBatch) Flush() error {
	wb.Lock()
	err := wb.commit()
	if err != nil {
		wb.Unlock()
		return err
	}
	wb.finished = true
	wb.txn.Discard()
	wb.Unlock()

	if err := wb.throttle.Finish(); err != nil {
		if wb.Error() != nil {
			return fmt.Errorf("wb.err: %w err: %w", wb.Error(), err)
		}
		return err
	}

	return wb.Error()
}

// Error returns any errors encountered so far. No commits would be run once an error is detected.
func (wb *WriteBatch) Error() error {
	// If the interface conversion fails, the err will be nil.
	err, _ := wb.err.Load().(error)
	return err
}

View on GitHub (pinned to 2a001d466f)

Solutions

  1. Inspect both wrapped errors with errors.Is/Unwrap to find the root cause (e.g. ErrDBClosed, ErrTxnTooBig)
  2. Call wb.Cancel() on error paths before closing the DB so pending writes don't fail mid-flush
  3. Check wb.Error() after each SetEntry loop iteration to fail fast before Flush

Example fix

// before
if err := wb.Flush(); err != nil { return err }
// after
if err := wb.Flush(); err != nil {
    if errors.Is(err, badger.ErrDBClosed) { /* DB closed during flush */ }
    log.Printf("flush failed: %v", err)
    return err
}
Defensive patterns

Strategy: try-catch

Validate before calling

if err := wb.Error(); err != nil { wb.Cancel(); return err } // before Flush
if db.IsClosed() { return badger.ErrDBClosed }

Try / catch

if err := wb.Flush(); err != nil {
    var unwrapped error
    for e := err; e != nil; unwrapped, e = e, errors.Unwrap(e) { log.Printf("cause: %v", unwrapped) }
    return err
}

Prevention

When it happens

Trigger: One or more SetEntry calls failed earlier (e.g. ErrTxnTooBig, key too large) AND throttle.Finish also returned an error (e.g. a commit failed, ErrDBClosed) when Flush drained the queue.

Common situations: Closing the DB while a WriteBatch is still flushing; oversized entries inflating batch past max size; disk full or IO errors during async commits.

Related errors


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