hyperledger/fabric · error

empty block data

Error message

empty block data

What it means

verifyBlockDataAndMetadata rejects any proposed block with nil Data or zero transactions. SmartBFT proposals must carry at least one request (except special cases handled elsewhere), so an empty block is treated as an invalid proposal.

Source

Thrown at orderer/consensus/smartbft/verifier.go:266

		return errors.Errorf("previous header hash is %s but expected %s", thisHdrHashOfPrevHdr, prevHeaderHash)
	}

	dataHash, err := protoutil.BlockDataHash(block.Data)
	if err != nil {
		return err
	}
	dataHashString := hex.EncodeToString(block.Header.DataHash)

	actualHashOfData := hex.EncodeToString(dataHash)
	if dataHashString != actualHashOfData {
		return errors.Errorf("data hash is %s but expected %s", dataHashString, actualHashOfData)
	}
	return nil
}

func (v *Verifier) verifyBlockDataAndMetadata(block *cb.Block, metadata []byte) ([]types.RequestInfo, error) {
	if block.Data == nil || len(block.Data.Data) == 0 {
		return nil, errors.New("empty block data")
	}

	if block.Metadata == nil || len(block.Metadata.Metadata) < len(cb.BlockMetadataIndex_name) {
		return nil, errors.New("block metadata is either missing or contains too few entries")
	}

	signatureMetadata, err := protoutil.GetMetadataFromBlock(block, cb.BlockMetadataIndex_SIGNATURES)
	if err != nil {
		return nil, err
	}
	ordererMetadataFromSignature := &cb.OrdererBlockMetadata{}
	if err := proto.Unmarshal(signatureMetadata.Value, ordererMetadataFromSignature); err != nil {
		return nil, errors.Wrap(err, "failed unmarshaling OrdererBlockMetadata")
	}

	// Ensure the view metadata in the block signature and in the proposal are the same

	metadataInBlock := &smartbftprotos.ViewMetadata{}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Fix the batcher/leader to only propose blocks containing at least one request
  2. Check the request-batching timeouts and queue: ensure requests are collected before proposing
  3. Validate the proposal bytes before calling VerifyProposal; discard empty proposals
  4. If seen after an upgrade, check for regressions in block assembly code

Example fix

// before
if len(pendingRequests) == 0 { propose(block) }
// after
if len(pendingRequests) == 0 { return } // do not propose an empty block
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

func hasBlockData(b *cb.Block) bool { return b != nil && b.Data != nil && len(b.Data.Data) > 0 }

Try / catch

if err := verifyProposal(...); err != nil && err.Error() == "empty block data" {
    logger.Warn("leader proposed an empty block; skip and await valid proposal")
}

Prevention

When it happens

Trigger: VerifyProposal receives a block where block.Data == nil or len(block.Data.Data) == 0 — e.g. a leader assembled a block with no batched requests and submitted it for verification.

Common situations: A leader bug assembling an empty batch; a proposal drained of its requests by faulty request batching logic; corrupted proposal deserialization losing the Data field; testing/misuse of VerifyProposal with a synthetic empty block.

Related errors


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