{"record":{"id":"477b2dadd734a440","repo":"hyperledger/fabric","slug":"empty-block-477b2d","errorCode":null,"errorMessage":"empty block","messagePattern":"empty block","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"orderer/consensus/smartbft/util.go","lineNumber":102,"sourceCode":"\n\treturn RuntimeConfig{\n\t\tconsenters:             nodeConf.consenters,\n\t\tBFTConfig:              bftConfig,\n\t\tisConfig:               true,\n\t\tid:                     rtc.id,\n\t\tlogger:                 rtc.logger,\n\t\tLastCommittedBlockHash: hex.EncodeToString(protoutil.BlockHeaderHash(block.Header)),\n\t\tNodes:                  nodeConf.nodeIDs,\n\t\tID2Identities:          nodeConf.id2Identities,\n\t\tRemoteNodes:            nodeConf.remoteNodes,\n\t\tLastBlock:              block,\n\t\tLastConfigBlock:        block,\n\t}, nil\n}\n\nfunc configBlockToBFTConfig(selfID uint64, block *cb.Block, bccsp bccsp.BCCSP) (types.Configuration, error) {\n\tif block == nil || block.Data == nil || len(block.Data.Data) == 0 {\n\t\treturn types.Configuration{}, errors.New(\"empty block\")\n\t}\n\n\tenv, err := protoutil.UnmarshalEnvelope(block.Data.Data[0])\n\tif err != nil {\n\t\treturn types.Configuration{}, err\n\t}\n\tbundle, err := channelconfig.NewBundleFromEnvelope(env, bccsp)\n\tif err != nil {\n\t\treturn types.Configuration{}, err\n\t}\n\n\toc, ok := bundle.OrdererConfig()\n\tif !ok {\n\t\treturn types.Configuration{}, errors.New(\"no orderer config\")\n\t}\n\n\tconsensusConfigOptions, err := createSmartBftConfig(oc)\n\tif err != nil {","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/consensus/smartbft/util.go#L84-L120","documentation":"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.","triggerScenarios":"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.","commonSituations":"Ledger corruption or misconfigured file ledger pointing at truncated blocks; a retriever returning the wrong (empty) block when resolving the last-config block number.","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"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"if block == nil || block.Data == nil || len(block.Data.Data) == 0 {\n  return errors.New(\"refusing to apply: config block has no data\")\n}","typeGuard":"func isNonEmptyBlock(b *cb.Block) bool { return b != nil && b.Data != nil && len(b.Data.Data) > 0 }","tryCatchPattern":"if err := chain.BlockCommitted(block); err != nil && strings.Contains(err.Error(), \"empty block\") {\n  logger.Panicf(\"ledger returned an empty config block; integrity check needed: %v\", err)\n}","preventionTips":["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"],"tags":["hyperledger-fabric","smartbft","ledger","config-block"],"backgroundTag":"empty-block","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}