dgraph-io/badger · critical

txn callback is nil

Error message

txn callback is nil

What it means

runTxnCallback is Badger's internal dispatcher for commit callbacks used by CommitWith. It panics if the *txnCb struct itself is nil, which indicates an internal wiring bug in the commit path rather than user error. This panic runs inside a goroutine spawned by CommitWith, so it crashes the process if reached.

Source

Thrown at txn.go:683

		return err
	}
	// If batchSet failed, LSM would not have been updated. So, no need to rollback anything.

	// TODO: What if some of the txns successfully make it to value log, but others fail.
	// Nothing gets updated to LSM, until a restart happens.
	return txnCb()
}

type txnCb struct {
	commit func() error
	user   func(error)
	err    error
}

func runTxnCallback(cb *txnCb) {
	switch {
	case cb == nil:
		panic("txn callback is nil")
	case cb.user == nil:
		panic("Must have caught a nil callback for txn.CommitWith")
	case cb.err != nil:
		cb.user(cb.err)
	case cb.commit != nil:
		err := cb.commit()
		cb.user(err)
	default:
		cb.user(nil)
	}
}

// CommitWith acts like Commit, but takes a callback, which gets run via a
// goroutine to avoid blocking this function. The callback is guaranteed to run,
// so it is safe to increment sync.WaitGroup before calling CommitWith, and
// decrementing it in the callback; to block until all callbacks are run.
func (txn *Txn) CommitWith(cb func(error)) {
	if cb == nil {

View on GitHub (pinned to 2a001d466f)

Solutions

  1. Check the Badger version for known bugs in the CommitWith empty-transaction path and upgrade
  2. Ensure you never call CommitWith with a nil callback (that produces error 52 before this one)
  3. If using a fork, verify runTxnCallback is only invoked with a non-nil *txnCb allocated by CommitWith

Example fix

// before (fork/internal)
runTxnCallback(nil)
// after
if cb != nil { runTxnCallback(cb) }
Defensive patterns

Strategy: validation

Validate before calling

if cb == nil { cb = func(error){} } // before any commit path involving CommitWith

Try / catch

defer func(){ if r := recover(); r != nil { log.Fatalf("badger txn callback panic: %v", r) } }() // around goroutines is not possible; guard at CommitWith call site

Prevention

When it happens

Trigger: A nil *txnCb reaches runTxnCallback; this only happens via internal misuse of the callback plumbing (e.g. committing an empty txn whose callback path constructs no txnCb, or a library bug/patched code path passing nil).

Common situations: Using CommitWith on a transaction with no pending writes combined with managed/Read-only txn setups in older versions; custom forks that call runTxnCallback directly.

Related errors


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