{"record":{"id":"153bf67de13d39d6","repo":"hyperledger/fabric","slug":"nil-block-or-nil-header","errorCode":null,"errorMessage":"nil block or nil header","messagePattern":"nil block or nil header","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/consensus/etcdraft/util.go","lineNumber":363,"sourceCode":"\t\treturn err\n\t}\n\n\treturn nil\n}\n\n// ConsenterCertificate denotes a TLS certificate of a consenter\ntype ConsenterCertificate struct {\n\tConsenterCertificate []byte\n\tCryptoProvider       bccsp.BCCSP\n\tLogger               *flogging.FabricLogger\n}\n\n// IsConsenterOfChannel returns whether the caller is a consenter of a channel\n// by inspecting the given configuration block.\n// It returns nil if true, else returns an error.\nfunc (conCert ConsenterCertificate) IsConsenterOfChannel(configBlock *common.Block) error {\n\tif configBlock == nil || configBlock.GetHeader() == nil {\n\t\treturn errors.New(\"nil block or nil header\")\n\t}\n\tenvelopeConfig, err := protoutil.ExtractEnvelope(configBlock, 0)\n\tif err != nil {\n\t\treturn err\n\t}\n\tbundle, err := channelconfig.NewBundleFromEnvelope(envelopeConfig, conCert.CryptoProvider)\n\tif err != nil {\n\t\treturn err\n\t}\n\toc, exists := bundle.OrdererConfig()\n\tif !exists {\n\t\treturn errors.New(\"no orderer config in bundle\")\n\t}\n\tm := &etcdraft.ConfigMetadata{}\n\tif err := proto.Unmarshal(oc.ConsensusMetadata(), m); err != nil {\n\t\treturn err\n\t}\n","sourceCodeStart":345,"sourceCodeEnd":381,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/consensus/etcdraft/util.go#L345-L381","documentation":"ConsenterCertificate.IsConsenterOfChannel checks whether this consenter's certificate appears in a channel's orderer config by inspecting a config block. It throws errors.New(\"nil block or nil header\") when the caller passes a configBlock that is nil or whose block header is nil, i.e. there is no usable block to inspect. It is a defensive precondition check before ExtractEnvelope.","triggerScenarios":"Calling IsConsenterOfChannel (e.g. during etcdraft chain start / cluster membership check) with a configBlock variable that was never populated or a zero-value common.Block whose Header was never set.","commonSituations":"Orderer startup before the genesis/config block was retrieved from the ledger or file; passing the result of a failed config-block lookup without checking for nil; unit tests constructing an empty &common.Block{}.","solutions":["Ensure a valid config block is loaded (from genesis file or ledger) before calling IsConsenterOfChannel","Check configBlock != nil && configBlock.GetHeader() != nil at the call site before invoking","Fix the bootstrap path so the genesis block is correctly read/decoded (correct file path, ORDERER_GENERAL_GENESISMETHOD etc.)"],"exampleFix":"// before\nerr := conCert.IsConsenterOfChannel(nil)\n// after\nconfigBlock := retrieveConfigBlock(ledger)\nif configBlock == nil || configBlock.GetHeader() == nil {\n    return errors.New(\"config block not available\")\n}\nerr := conCert.IsConsenterOfChannel(configBlock)","handlingStrategy":"type-guard","validationCode":"if configBlock == nil || configBlock.GetHeader() == nil {\n    return errors.New(\"valid config block required\")\n}","typeGuard":"func isValidBlock(b *common.Block) bool {\n    return b != nil && b.GetHeader() != nil\n}","tryCatchPattern":null,"preventionTips":["Always load the genesis/config block before membership checks","Check errors from block-retrieval functions instead of using possibly-nil results","Add nil-header assertions in tests for block-producing code"],"tags":["hyperledger-fabric","etcdraft","nil-pointer","config-block"],"backgroundTag":"nil-block-header","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"}