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
- Verify ledger integrity for the channel; restore the config block from a peer/orderer snapshot if corrupted
- Ensure the block being passed is the actual config block identified by the last-config index metadata
- Restart the orderer and check file ledger directory permissions and disk health
- 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
- Verify last-config index metadata before using a block as a config block
- Monitor ledger/disk health and enable integrity checks
- Never construct config blocks manually; use genesis/config update tooling
- Restore channels from snapshots instead of patching truncated ledgers
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
- remote nodes cannot be computed, rejecting config block
- failed unmarshalling envelope of config block
- failed getting a new bundle from envelope of config block
- no channel configuration found in the config block
- consenter options type mismatch
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/477b2dadd734a440.
Report an issue: GitHub.