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
- Check that the block was fully populated by its producer before calling; log the block number and data length
- Reject empty blocks upstream (before hashing) with a descriptive error
- If the block came from a ledger, treat it as corrupt and re-fetch or rebuild
- 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
- Validate block structure immediately after decode, before hashing
- In tests, always populate Data with at least one envelope or a config tx
- Treat empty blocks from a ledger as corruption and re-fetch
- Check HasConfigTx expectations when a block should be a config block
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
- %s is mandatory and cannot be empty
- enrollment certificate isn't a valid PEM block
- failed to decode PEM block from %s
- '%s' not equal <newest|oldest|config|(number)>
- unmarshalling block: %s
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/f8a5fc93b383babe.
Report an issue: GitHub.