hyperledger/fabric · error

nil block

Error message

nil block

What it means

ConfigEnvelopeFromBlock returns this error when called with a nil *common.Block. It is a defensive guard: no envelope can be extracted from a nonexistent block, so the function fails fast with a plain sentinel error.

Source

Thrown at orderer/consensus/etcdraft/util.go:153

func ConfigChannelHeader(block *common.Block) (hdr *common.ChannelHeader, err error) {
	envelope, err := protoutil.ExtractEnvelope(block, 0)
	if err != nil {
		return nil, errors.Wrap(err, "failed to extract envelope from the block")
	}

	channelHeader, err := protoutil.ChannelHeader(envelope)
	if err != nil {
		return nil, errors.Wrap(err, "cannot extract channel header")
	}

	return channelHeader, nil
}

// ConfigEnvelopeFromBlock extracts configuration envelope from the block based on the
// config type, i.e. HeaderType_ORDERER_TRANSACTION or HeaderType_CONFIG
func ConfigEnvelopeFromBlock(block *common.Block) (*common.Envelope, error) {
	if block == nil {
		return nil, errors.New("nil block")
	}

	envelope, err := protoutil.ExtractEnvelope(block, 0)
	if err != nil {
		return nil, errors.Wrapf(err, "failed to extract envelope from the block")
	}

	channelHeader, err := protoutil.ChannelHeader(envelope)
	if err != nil {
		return nil, errors.Wrap(err, "cannot extract channel header")
	}

	switch channelHeader.GetType() {
	case int32(common.HeaderType_ORDERER_TRANSACTION):
		return nil, errors.Errorf("unsupported legacy system channel header type: %v", channelHeader.GetType())
	case int32(common.HeaderType_CONFIG):
		return envelope, nil
	default:

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Check for nil before calling: only invoke ConsensusMetadataFromConfigBlock / ConfigEnvelopeFromBlock with a block confirmed non-nil.
  2. Fix the upstream block-retrieval path so a missing block is surfaced as an error instead of (nil, nil).
  3. In tests, ensure block fixtures are actually assigned before use.

Example fix

// before
block, _ := ledger.GetBlockByNumber(5) // may be nil
meta, _, err := ConsensusMetadataFromConfigBlock(block)

// after
block, err := ledger.GetBlockByNumber(5)
if err != nil {
    return err
}
if block == nil {
    return errors.New("block 5 not found in ledger")
}
meta, _, err := ConsensusMetadataFromConfigBlock(block)
Defensive patterns

Strategy: type-guard

Validate before calling

if block == nil {
    return errors.New("config block is nil")
}

Type guard

func nonNilBlock(block *common.Block) bool {
    return block != nil && block.Header != nil && block.Data != nil
}

Try / catch

envelope, err := ConfigEnvelopeFromBlock(block)
if err != nil {
    if err.Error() == "nil block" {
        return errors.New("block retrieval returned nothing")
    }
    return err
}

Prevention

When it happens

Trigger: Passing a nil block into ConfigEnvelopeFromBlock, usually indirectly via ConsensusMetadataFromConfigBlock when the caller obtained a nil block (e.g. a failed GetBlockById/RetrieveBlock returned nil without an error).

Common situations: Ledger/block retrieval returning (nil, nil); chain puller logic handing through a missing block; ordering system channel removal flows reading a block that was never written.

Related errors


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