dgraph-io/badger · error

ErrEmptyKey

ErrEmptyKey

Error message

Key cannot be empty

What it means

ErrEmptyKey is returned when an update function is given a key of length zero (errors.go:40). Both Txn.modify (txn.go:360) and the IndexCache/Get path (db.go:1437) reject empty keys since Badger cannot store or look them up meaningfully.

Source

Thrown at errors.go:40

	// ErrKeyNotFound is returned when key isn't found on a txn.Get.
	ErrKeyNotFound = stderrors.New("Key not found")

	// ErrTxnTooBig is returned if too many writes are fit into a single transaction.
	ErrTxnTooBig = stderrors.New("Txn is too big to fit into one request")

	// ErrConflict is returned when a transaction conflicts with another transaction. This can
	// happen if the read rows had been updated concurrently by another transaction.
	ErrConflict = stderrors.New("Transaction Conflict. Please retry")

	// ErrReadOnlyTxn is returned if an update function is called on a read-only transaction.
	ErrReadOnlyTxn = stderrors.New("No sets or deletes are allowed in a read-only transaction")

	// ErrDiscardedTxn is returned if a previously discarded transaction is reused.
	ErrDiscardedTxn = stderrors.New("This transaction has been discarded. Create a new one")

	// ErrEmptyKey is returned if an empty key is passed on an update function.
	ErrEmptyKey = stderrors.New("Key cannot be empty")

	// ErrInvalidKey is returned if the key has a special !badger! prefix,
	// reserved for internal usage.
	ErrInvalidKey = stderrors.New("Key is using a reserved !badger! prefix")

	// ErrBannedKey is returned if the read/write key belongs to any banned namespace.
	ErrBannedKey = stderrors.New("Key is using the banned prefix")

	// ErrThresholdZero is returned if threshold is set to zero, and value log GC is called.
	// In such a case, GC can't be run.
	ErrThresholdZero = stderrors.New(
		"Value log GC can't run because threshold is set to zero")

	// ErrNoRewrite is returned if a call for value log GC doesn't result in a log file rewrite.
	ErrNoRewrite = stderrors.New(
		"Value log GC attempt didn't result in any cleanup")

	// ErrRejected is returned if a value log GC is called either while another GC is running, or

View on GitHub (pinned to 2a001d466f)

Solutions

  1. Validate len(key) > 0 before calling Set/Delete/Get and skip or error on your side
  2. Fix key construction so every key has a non-empty prefix/field
  3. Guard against nil slices (a nil []byte has len 0)

Example fix

// before
txn.Set(key, value) // key may be empty -> ErrEmptyKey
// after
if len(key) == 0 {
    return fmt.Errorf("skipping record with empty key")
}
txn.Set(key, value)
Defensive patterns

Strategy: validation

Validate before calling

if len(key) == 0 {
    return errors.New("refusing DB write with empty key")
}

Type guard

func validKey(key []byte) bool { return len(key) > 0 && !bytes.HasPrefix(key, []byte("!badger!")) }

Try / catch

if err := txn.Set(key, val); err != nil {
    if errors.Is(err, badger.ErrEmptyKey) {
        return fmt.Errorf("empty key for record %v: %w", rec, err)
    }
    return err
}

Prevention

When it happens

Trigger: txn.Set(nil, val) or txn.Set([]byte{}, val); txn.Delete with an empty key; GetIndexFor/lookup APIs (db.go:1437) receiving an empty key; a variable holding a key that was never populated.

Common situations: Dynamic key construction where a prefix/format produced "", unmarshalling records with missing fields into keys, nil byte slices from earlier failed operations.

Related errors


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