hyperledger/fabric · error

empty block

Error message

empty block

What it means

The builtin default validation plugin's Validate inspects the block given by the committer, expecting a non-nil block with non-nil Data. It returns 'empty block' when the block itself or its Data payload is nil, i.e. there is nothing to validate.

Source

Thrown at core/handlers/validation/builtin/default_validation.go:58

	TxValidatorV2_0 TransactionValidator
}

//go:generate mockery -dir . -name TransactionValidator -case underscore -output mocks/
type TransactionValidator interface {
	Validate(block *common.Block, namespace string, txPosition int, actionPosition int, policy []byte) commonerrors.TxValidationError
}

func (v *DefaultValidation) Validate(block *common.Block, namespace string, txPosition int, actionPosition int, contextData ...validation.ContextDatum) error {
	if len(contextData) == 0 {
		logger.Panicf("Expected to receive policy bytes in context data")
	}

	serializedPolicy, isSerializedPolicy := contextData[0].(vp.SerializedPolicy)
	if !isSerializedPolicy {
		logger.Panicf("Expected to receive a serialized policy in the first context data")
	}
	if block == nil || block.Data == nil {
		return errors.New("empty block")
	}
	if txPosition >= len(block.Data.Data) {
		return errors.Errorf("block has only %d transactions, but requested tx at position %d", len(block.Data.Data), txPosition)
	}
	if block.Header == nil {
		return errors.Errorf("no block header")
	}

	var err error
	switch {
	case v.Capabilities.V2_0Validation():
		err = v.TxValidatorV2_0.Validate(block, namespace, txPosition, actionPosition, serializedPolicy.Bytes())

	case v.Capabilities.V1_3Validation():
		err = v.TxValidatorV1_3.Validate(block, namespace, txPosition, actionPosition, serializedPolicy.Bytes())

	case v.Capabilities.V1_2Validation():
		fallthrough

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Inspect the peer log around commit time to find which component supplied the nil/empty block
  2. Run ledger integrity checks (peer node rebuild-dbs or restore from a good snapshot/backup)
  3. Fix the calling test/harness to pass a constructed common.Block with Data populated
  4. Report or fix upstream if the committer can legitimately produce nil blocks

Example fix

// before: test passes a bare block
err := validator.Validate(&common.Block{}, "ns", 0, 0, policy) // empty block
// after: include Data and Header
block := &common.Block{Header: &common.BlockHeader{}, Data: &common.BlockData{Data: [][]byte{envelopeBytes}}}
err := validator.Validate(block, "ns", 0, 0, policy)
Defensive patterns

Strategy: validation

Validate before calling

func validateBlockInput(block *common.Block, ns string, txPos, actionPos int) error {
    if block == nil || block.Data == nil {
        return errors.New("empty block: refusing validation")
    }
    return nil
}
// call before plugin.Validate(...)

Type guard

func hasBlockData(b *common.Block) bool {
    return b != nil && b.Data != nil
}

Try / catch

if err := v.Validate(block, ns, txPos, actionPos, policy); err != nil {
    if err.Error() == "empty block" {
        logger.Errorf("committer supplied empty block; check ledger integrity")
    }
    return err
}

Prevention

When it happens

Trigger: Validate (called by the committer's validation path, TestErrorConversion, TestValidateBadInput) is invoked with block == nil or block.Data == nil, or contextData[0] is not a serialized policy (that case panics instead), during block commit validation.

Common situations: A bug in the committer delivering malformed blocks; corrupted block storage after crash; test harness invoking the plugin with fabricated/nil blocks; ledger state issues after an unclean shutdown.

Related errors


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