hyperledger/fabric · error

error retrieving leveldb key [%#v]

Error message

error retrieving leveldb key [%#v]

What it means

DB.Get wraps any goleveldb Get error other than ErrNotFound (which is treated as a nil value, not an error) with the offending key. It means the key lookup failed for a reason other than absence: DB closed, corruption, or I/O error. Logged via logger.Errorf before being returned wrapped.

Source

Thrown at common/ledger/util/leveldbhelper/leveldb_helper.go:115

		return
	}
	if err := dbInst.db.Close(); err != nil {
		logger.Errorf("Error closing leveldb: %s", err)
	}
	dbInst.dbState = closed
}

// Get returns the value for the given key
func (dbInst *DB) Get(key []byte) ([]byte, error) {
	dbInst.mutex.RLock()
	defer dbInst.mutex.RUnlock()
	value, err := dbInst.db.Get(key, dbInst.readOpts)
	if errors.Is(err, leveldb.ErrNotFound) {
		return nil, nil
	}
	if err != nil {
		logger.Errorf("Error retrieving leveldb key [%#v]: %s", key, err)
		return nil, errors.Wrapf(err, "error retrieving leveldb key [%#v]", key)
	}
	// Previously the goleveldb library returned []byte{}
	// Now it returns []byte(nil)
	// NB!!! Because of the above changed behavior when there is no key in the database.
	// Here we simulate the desired behavior that the key is in the database.
	if value == nil {
		value = []byte{}
	}
	return value, nil
}

// Put saves the key/value
func (dbInst *DB) Put(key []byte, value []byte, sync bool) error {
	dbInst.mutex.RLock()
	defer dbInst.mutex.RUnlock()
	wo := dbInst.writeOptsNoSync
	if sync {
		wo = dbInst.writeOptsSync

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Check the wrapped error with errors.Is/errors.As for leveldb corruption or ErrClosed.
  2. Ensure the DB instance is opened for the lifetime of all callers (no premature Close).
  3. If corruption is reported, restore from backup or re-create the ledger database.
  4. Verify disk/filesystem health and permissions on the DB path.

Example fix

// before
value, err := db.Get(key)
if err != nil { return err }
// after
value, err := db.Get(key)
if err != nil {
  if errors.Is(err, leveldb.ErrClosed) {
    return fmt.Errorf("leveldb closed before Get of key %#v", key)
  }
  return err
}
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure DB lifetime covers usage
db, err := openProvider()
if err != nil { return err }
defer db.Close() // close only after all Gets are done

Type guard

func isGetErr(err error) bool {
  return err != nil && strings.Contains(err.Error(), "error retrieving leveldb key")
}

Try / catch

value, err := db.Get(key)
if err != nil {
  // ErrNotFound already returned as (nil, nil); anything here is a real failure
  return fmt.Errorf("leveldb get of %#v failed: %w", key, err)
}

Prevention

When it happens

Trigger: Calling Get after the DB was closed; leveldb reports corruption in a data block; read I/O failure on the DB files; passing a nil/invalid key is possible but errors are usually storage-related.

Common situations: Using a DB handle after provider close during peer shutdown; corrupted leveldb after unclean shutdown; read-only or failing disk mounts.

Related errors


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/7a9d93eb8482d301. Report an issue: GitHub.