hyperledger/fabric · error
block data is nil
Error message
block data is nil
What it means
ExtractEnvelope returns this error when the supplied *cb.Block has a nil Data field, i.e. the block carries no transaction data section at all. A well-formed Fabric block always has a non-nil Data (possibly empty), so a nil Data indicates an uninitialized or malformed block struct.
Source
Thrown at protoutil/commonutils.go:97
err = errors.Wrapf(err, "error unmarshalling message for type %s", headerType)
return chdr, err
}
// ExtractEnvelopeOrPanic retrieves the requested envelope from a given block
// and unmarshals it -- it panics if either of these operations fail
func ExtractEnvelopeOrPanic(block *cb.Block, index int) *cb.Envelope {
envelope, err := ExtractEnvelope(block, index)
if err != nil {
panic(err)
}
return envelope
}
// ExtractEnvelope retrieves the requested envelope from a given block and
// unmarshals it
func ExtractEnvelope(block *cb.Block, index int) (*cb.Envelope, error) {
if block.Data == nil {
return nil, errors.New("block data is nil")
}
envelopeCount := len(block.Data.Data)
if index < 0 || index >= envelopeCount {
return nil, errors.New("envelope index out of bounds")
}
marshaledEnvelope := block.Data.Data[index]
envelope, err := GetEnvelopeFromBlock(marshaledEnvelope)
err = errors.WithMessagef(err, "block data does not carry an envelope at index %d", index)
return envelope, err
}
// MakeChannelHeader creates a ChannelHeader.
func MakeChannelHeader(headerType cb.HeaderType, version int32, chainID string, epoch uint64) *cb.ChannelHeader {
tm := timestamppb.Now()
tm.Nanos = 0
return &cb.ChannelHeader{
Type: int32(headerType),View on GitHub (pinned to 2736b63f8f)
Solutions
- Check block.Data for nil (and len(block.Data.Data)) before calling ExtractEnvelope, or use IsConfigBlock-style nil checks.
- Trace where the block was produced/decoded — fix the source to always populate Data (e.g. use protoutil.NewBlock).
- If read from disk, validate the ledger storage; a truncated serialization can yield a Data-less block.
- For genesis-like empty blocks, special-case index access instead of calling ExtractEnvelope.
Example fix
// before
env, err := protoutil.ExtractEnvelope(block, 0) // 'block data is nil' on empty struct
// after
if block.Data == nil || len(block.Data.Data) == 0 {
return fmt.Errorf("block %d has no data", block.Header.Number)
}
env, err := protoutil.ExtractEnvelope(block, 0) Defensive patterns
Strategy: validation
Validate before calling
if block == nil || block.Data == nil {
return errors.New("refusing to extract: block has nil Data")
}
env, err := protoutil.ExtractEnvelope(block, index) Type guard
func blockHasData(block *cb.Block) bool {
return block != nil && block.Data != nil
} Try / catch
env, err := protoutil.ExtractEnvelope(block, 0)
if err != nil {
if err.Error() == "block data is nil" {
return fmt.Errorf("block %d is malformed (no data section)", block.GetHeader().GetNumber())
}
return err
} Prevention
- Never construct *cb.Block by hand; use protoutil.NewBlock so Data is initialized
- Validate blocks decoded from disk/network before use
- Treat a nil Data block as a storage-integrity signal and re-fetch from the ordering service
- Check IsConfigBlock-style nil guards as a habit before block accessors
When it happens
Trigger: Passing a *cb.Block created as &cb.Block{} or decoded from an empty/truncated byte slice to ExtractEnvelope, before the len() bounds check can run.
Common situations: Hand-constructed blocks in tests, blocks deserialized from a corrupted file ledger, APIs that return a bare Block without data on failure, block protos partially populated by external tooling.
Related errors
- block must be different from nil, channel=%s
- Invalid signed proposal during check policy on channel [%s]
- proto: Marshal called with nil
- chaincode interest is nil
- received nil proposal response
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/6389be594df0bf18.
Report an issue: GitHub.