hyperledger/fabric · error

empty block

Error message

empty block

What it means

VerifyTransactionsAreWellFormed checks that every envelope in a block's data can be parsed. If the BlockData pointer, its Data slice, or the slice contents are absent, there is nothing to validate, so it returns this error. It is a structural guard ensuring blocks handed to hashing/verification contain transactions.

Source

Thrown at protoutil/blockutils.go:318

		return policy.EvaluateSignedData(signatureSet)
	}
}

func searchConsenterIdentityByID(consenters []*cb.Consenter, identifier uint32) []byte {
	for _, consenter := range consenters {
		if consenter.Id == identifier {
			return MarshalOrPanic(&msp.SerializedIdentity{
				Mspid:   consenter.MspId,
				IdBytes: consenter.Identity,
			})
		}
	}
	return nil
}

func VerifyTransactionsAreWellFormed(bd *cb.BlockData) error {
	if bd == nil || bd.Data == nil || len(bd.Data) == 0 {
		return errors.New("empty block")
	}

	// If we have a single transaction, and the block is a config block, then no need to check
	// well formed-ness, because there cannot be another transaction in the original block.
	if HasConfigTx(bd) {
		return nil
	}

	for i, rawTx := range bd.Data {
		env := &cb.Envelope{}
		if err := proto.Unmarshal(rawTx, env); err != nil {
			return fmt.Errorf("transaction %d is invalid: %v", i, err)
		}

		if len(env.Payload) == 0 {
			return fmt.Errorf("transaction %d has no payload", i)
		}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Check that the block was fully populated by its producer before calling; log the block number and data length
  2. Reject empty blocks upstream (before hashing) with a descriptive error
  3. If the block came from a ledger, treat it as corrupt and re-fetch or rebuild
  4. In tests, seed cb.BlockData with at least one valid envelope or a config transaction

Example fix

// before
err := VerifyTransactionsAreWellFormed(block.Data)
// after
if block == nil || block.Data == nil || len(block.Data.Data) == 0 {
    return errors.Errorf("block %v has empty data; refusing to hash/verify", block)
}
err := VerifyTransactionsAreWellFormed(block.Data)
Defensive patterns

Strategy: validation

Validate before calling

if block == nil || block.Data == nil || len(block.Data.Data) == 0 {
    return errors.New("refusing to verify/hash an empty block")
}
err := VerifyTransactionsAreWellFormed(block.Data)

Type guard

func isNonEmptyBlockData(bd *cb.BlockData) bool {
    return bd != nil && bd.Data != nil && len(bd.Data) > 0
}

Try / catch

if err := VerifyTransactionsAreWellFormed(block.Data); err != nil {
    return fmt.Errorf("block %d not well formed: %w", block.GetHeader().GetNumber(), err)
}

Prevention

When it happens

Trigger: Calling VerifyTransactionsAreWellFormed with a nil *cb.BlockData, a nil Data field, or a zero-length Data slice — e.g. a block constructed without data or a decoded block missing payload bytes.

Common situations: Test harnesses creating empty blocks, ledger code reading a truncated/empty block record, or plumbing bugs where the envelope slice is dropped before hashing (BlockDataHash path).

Related errors


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