hyperledger/fabric · critical

empty block

Error message

empty block

What it means

configBlockToBFTConfig requires a config block with actual payload data to extract the orderer configuration. If the block is nil, has nil Data, or Data.Data is empty, it returns 'empty block' rather than dereferencing nil, since no configuration can be derived from a block with no envelope.

Source

Thrown at orderer/consensus/smartbft/util.go:102

	return RuntimeConfig{
		consenters:             nodeConf.consenters,
		BFTConfig:              bftConfig,
		isConfig:               true,
		id:                     rtc.id,
		logger:                 rtc.logger,
		LastCommittedBlockHash: hex.EncodeToString(protoutil.BlockHeaderHash(block.Header)),
		Nodes:                  nodeConf.nodeIDs,
		ID2Identities:          nodeConf.id2Identities,
		RemoteNodes:            nodeConf.remoteNodes,
		LastBlock:              block,
		LastConfigBlock:        block,
	}, nil
}

func configBlockToBFTConfig(selfID uint64, block *cb.Block, bccsp bccsp.BCCSP) (types.Configuration, error) {
	if block == nil || block.Data == nil || len(block.Data.Data) == 0 {
		return types.Configuration{}, errors.New("empty block")
	}

	env, err := protoutil.UnmarshalEnvelope(block.Data.Data[0])
	if err != nil {
		return types.Configuration{}, err
	}
	bundle, err := channelconfig.NewBundleFromEnvelope(env, bccsp)
	if err != nil {
		return types.Configuration{}, err
	}

	oc, ok := bundle.OrdererConfig()
	if !ok {
		return types.Configuration{}, errors.New("no orderer config")
	}

	consensusConfigOptions, err := createSmartBftConfig(oc)
	if err != nil {

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Verify ledger integrity for the channel; restore the config block from a peer/orderer snapshot if corrupted
  2. Ensure the block being passed is the actual config block identified by the last-config index metadata
  3. Restart the orderer and check file ledger directory permissions and disk health
  4. Regenerate genesis block for a new channel if the genesis block itself is empty
Defensive patterns

Strategy: type-guard

Validate before calling

if block == nil || block.Data == nil || len(block.Data.Data) == 0 {
  return errors.New("refusing to apply: config block has no data")
}

Type guard

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

Try / catch

if err := chain.BlockCommitted(block); err != nil && strings.Contains(err.Error(), "empty block") {
  logger.Panicf("ledger returned an empty config block; integrity check needed: %v", err)
}

Prevention

When it happens

Trigger: BlockCommitted on a config update where the retrieved config block has no data — typically a bug or corrupted ledger: nil block passed from retrieval, genesis block with empty data, or reading a block whose payloads were pruned/truncated.

Common situations: Ledger corruption or misconfigured file ledger pointing at truncated blocks; a retriever returning the wrong (empty) block when resolving the last-config block number.

Related errors


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