{"record":{"id":"30a74bb214f1ffe8","repo":"hyperledger/fabric","slug":"block-data-is-nil-30a74b","errorCode":null,"errorMessage":"block data is nil","messagePattern":"block data is nil","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/common/follower/follower_chain.go","lineNumber":183,"sourceCode":"\t\t}\n\t\tif err := blockPullerFactory.UpdateVerifierFromConfigBlock(chain.lastConfig); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\n\tif joinBlock == nil {\n\t\tchain.status = types.StatusActive\n\t\tif isMem, _ := chain.clusterConsenter.IsChannelMember(chain.lastConfig); isMem {\n\t\t\tchain.consensusRelation = types.ConsensusRelationConsenter\n\t\t}\n\n\t\tchain.logger.Infof(\"Created with a nil join-block, ledger height: %d\", chain.firstHeight)\n\t} else {\n\t\tif joinBlock.Header == nil {\n\t\t\treturn nil, errors.New(\"block header is nil\")\n\t\t}\n\t\tif joinBlock.Data == nil {\n\t\t\treturn nil, errors.New(\"block data is nil\")\n\t\t}\n\n\t\t// Check the block puller creation function once before we start the follower. This ensures we can extract\n\t\t// the endpoints from the join-block.\n\t\tpuller, err := blockPullerFactory.BlockPuller(joinBlock, nil)\n\t\tif err != nil {\n\t\t\treturn nil, errors.WithMessage(err, \"error creating a block puller from join-block\")\n\t\t}\n\t\tpuller.Close()\n\n\t\tif chain.joinBlock.Header.Number < chain.ledgerResources.Height() {\n\t\t\tchain.status = types.StatusActive\n\t\t}\n\t\tif isMem, _ := chain.clusterConsenter.IsChannelMember(chain.joinBlock); isMem {\n\t\t\tchain.consensusRelation = types.ConsensusRelationConsenter\n\t\t}\n\n\t\tchain.logger.Infof(\"Created with join-block number: %d, ledger height: %d\", joinBlock.Header.Number, chain.firstHeight)","sourceCodeStart":165,"sourceCodeEnd":201,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/common/follower/follower_chain.go#L165-L201","documentation":"NewChain requires the join block to carry Data because it derives configuration and endpoints (for the block puller) from the block's payload. A block with a Header but nil Data is incomplete and cannot be used to bootstrap the follower, so creation fails.","triggerScenarios":"Calling NewChain with a joinBlock that has a Header but nil Data — e.g. a block assembled from only a header, a corrupted payload, or unmarshaling that partially failed.","commonSituations":"Hand-crafted join blocks in tests missing Data; truncated block files used with osnadmin join; snapshot/restore tooling writing header-only blocks; corruption during transfer of the join block.","solutions":["Provide a complete block (Header + Data + Metadata), typically a config block, as the join block","Re-obtain the join block from a healthy orderer or the channel's genesis/config block source","Check unmarshal errors when deserializing the join block; do not ignore partial failures","If hand-constructing, populate Data with the marshaled Payload of the config block"],"exampleFix":"// before\njoinBlock := &common.Block{Header: &common.BlockHeader{Number: 5}}\nchain, err := follower.NewChain(..., joinBlock, ...)\n// after\nenv := configBlockEnvelope // config envelope from a valid source\npayloadMarshal, _ := proto.Marshal(env)\ndata, _ := proto.Marshal(&common.Payload{Header: hdr, Data: payloadMarshal})\njoinBlock := &common.Block{Header: &common.BlockHeader{Number: 5}, Data: &common.BlockData{Data: [][]byte{data}}}\nchain, err := follower.NewChain(..., joinBlock, ...)","handlingStrategy":"validation","validationCode":"func validJoinBlock(b *common.Block) error {\n    if b == nil || b.Header == nil {\n        return errors.New(\"join block missing header\")\n    }\n    if b.Data == nil || len(b.Data.Data) == 0 {\n        return errors.New(\"join block has no data payload\")\n    }\n    return nil\n}\n// run before follower.NewChain(..., joinBlock, ...)","typeGuard":"func hasPayload(b *common.Block) bool {\n    return b != nil && b.Data != nil && len(b.Data.Data) > 0\n}","tryCatchPattern":"chain, err := follower.NewChain(..., joinBlock, ...)\nif err != nil {\n    if err.Error() == \"block data is nil\" {\n        return fmt.Errorf(\"join block lacks data payload; use a full config block\")\n    }\n    return err\n}","preventionTips":["Always join with a complete config block (header + data + metadata), never header-only blocks","Re-export join blocks from a healthy orderer if the file appears truncated","Handle Unmarshal errors; partial decodes yield blocks with missing fields","In tests, build blocks with both Header and Data populated"],"tags":["follower","join-block","malformed-data"],"backgroundTag":"nil-block-data","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"}