{"record":{"id":"e30071d1a6457d52","repo":"hyperledger/fabric","slug":"nil-block-e30071","errorCode":null,"errorMessage":"nil block","messagePattern":"nil block","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/consensus/smartbft/consenter.go","lineNumber":250,"sourceCode":"\t\tc.MetricsWalBFT,\n\t\tc.BCCSP,\n\t\tegressCommFactory,\n\t\t&synchronizerCreator{},\n\t)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"failed creating a new BFTChain\")\n\t}\n\n\t// refresh cluster service with updated consenters\n\tc.ClusterService.ConfigureNodeCerts(chain.Channel, consenters)\n\tchain.ClusterService = c.ClusterService\n\n\treturn chain, nil\n}\n\nfunc (c *Consenter) IsChannelMember(joinBlock *cb.Block) (bool, error) {\n\tif joinBlock == nil {\n\t\treturn false, errors.New(\"nil block\")\n\t}\n\tenvelopeConfig, err := protoutil.ExtractEnvelope(joinBlock, 0)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\tbundle, err := channelconfig.NewBundleFromEnvelope(envelopeConfig, c.BCCSP)\n\tif err != nil {\n\t\treturn false, err\n\t}\n\toc, exists := bundle.OrdererConfig()\n\tif !exists {\n\t\treturn false, errors.New(\"no orderer config in bundle\")\n\t}\n\tmember := false\n\n\tsantizedCert, err := crypto.SanitizeX509Cert(c.Identity)\n\tif err != nil {\n\t\treturn false, err","sourceCodeStart":232,"sourceCodeEnd":268,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/consensus/smartbft/consenter.go#L232-L268","documentation":"IsChannelMember inspects a join block to determine whether this orderer is a member of the channel. It requires a non-nil block; passing nil yields this error immediately before any envelope extraction.","triggerScenarios":"Calling IsChannelMember (e.g. during channel participation / follower creation decisions in HandleJoinChain) with a nil *cb.Block — typically when no join/config block was supplied to the osnadmin channel join API or an internal caller resolved no config block.","commonSituations":"`osnadmin channel join` invoked without --config-block or with a failure to read the block file; an internal code path passing a nil latest config block because the ledger lookup failed; scripting that sends an empty join request body.","solutions":["Supply a valid genesis or latest config block: osnadmin channel join --channel-id <ch> --config-block <file.block>","Verify the block file exists and is a non-empty marshaled common.Block (check with configtxlator or peek)","Fix the internal caller that resolved nil (ensure the ledger/chain retrieval returns the config block before calling IsChannelMember)"],"exampleFix":"// before\njoinBlock := maybeLoadBlock(path) // may return nil\nmember, err := consenter.IsChannelMember(joinBlock)\n\n// after\njoinBlock, err := loadBlock(path)\nif err != nil || joinBlock == nil {\n    return errors.New(\"config block required for channel join\")\n}\nmember, err := consenter.IsChannelMember(joinBlock)","handlingStrategy":"type-guard","validationCode":"if joinBlock == nil {\n    return errors.New(\"a config block is required to join the channel\")\n}\nif joinBlock.Header == nil || len(joinBlock.Data.Data) == 0 {\n    return errors.New(\"config block is empty or malformed\")\n}","typeGuard":"func isValidBlock(b *cb.Block) bool {\n    return b != nil && b.Header != nil && len(b.Data.GetData()) > 0\n}\n// call: if !isValidBlock(joinBlock) { return errors.New(\"nil/invalid block\") }","tryCatchPattern":null,"preventionTips":["Always pass --config-block to osnadmin channel join","Verify block files are non-empty and decode as common.Block before use","Script joins to fail fast when the block file is missing"],"tags":["fabric","smartbft","channel-join","input-validation"],"backgroundTag":"nil-config-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"}