{"record":{"id":"a3abca3763578ab2","repo":"hyperledger/fabric","slug":"last-config-is-nil","errorCode":null,"errorMessage":"last config is nil","messagePattern":"last config is nil","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/consensus/smartbft/verifier.go","lineNumber":311,"sourceCode":"\n\tif !proto.Equal(metadataInBlock, metadataFromProposal) {\n\t\treturn nil, errors.Errorf(\n\t\t\t\"expected metadata in block to be [view_id:%d latest_sequence:%d] but got [view_id:%d latest_sequence:%d]\",\n\t\t\tmetadataFromProposal.GetViewId(), metadataFromProposal.GetLatestSequence(),\n\t\t\tmetadataInBlock.GetViewId(), metadataInBlock.GetLatestSequence(),\n\t\t)\n\t}\n\n\trtc := v.RuntimeConfig.Load().(RuntimeConfig)\n\tlastConfig := rtc.LastConfigBlock.Header.Number\n\n\tif protoutil.IsConfigBlock(block) {\n\t\tlastConfig = block.Header.Number\n\t}\n\n\t// Verify last config\n\tif ordererMetadataFromSignature.LastConfig == nil {\n\t\treturn nil, errors.Errorf(\"last config is nil\")\n\t}\n\n\tif ordererMetadataFromSignature.LastConfig.Index != lastConfig {\n\t\treturn nil, errors.Errorf(\"last config in block orderer metadata points to %d but our persisted last config is %d\", ordererMetadataFromSignature.LastConfig.Index, lastConfig)\n\t}\n\n\trawLastConfig, err := protoutil.GetMetadataFromBlock(block, cb.BlockMetadataIndex_LAST_CONFIG)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tlastConf := &cb.LastConfig{}\n\tif err := proto.Unmarshal(rawLastConfig.Value, lastConf); err != nil {\n\t\treturn nil, err\n\t}\n\tif lastConf.Index != lastConfig {\n\t\treturn nil, errors.Errorf(\"last config in block metadata points to %d but our persisted last config is %d\", ordererMetadataFromSignature.LastConfig.Index, lastConfig)\n\t}\n","sourceCodeStart":293,"sourceCodeEnd":329,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/consensus/smartbft/verifier.go#L293-L329","documentation":"SmartBFT blocks carry OrdererBlockMetadata inside the block's orderer metadata, including a LastConfig index pointing at the block number of the most recent config block. verifyBlockDataAndMetadata computes the expected last-config index (persisted or, for config blocks, the block's own number) and first checks that the signed metadata actually contains a LastConfig. This error means the OrdererBlockMetadata signature metadata has a nil LastConfig field, so the verifier cannot validate the block's config lineage.","triggerScenarios":"VerifyProposal -> verifyBlockDataAndMetadata: for a block being verified, ordererMetadataFromSignature.LastConfig is nil (the proto field was never populated by the proposer), regardless of whether the block is a config or normal block.","commonSituations":"A proposer built the block with an older/different code path that omits LastConfig; corrupted block metadata bytes; a hand-crafted or replayed proposal from a non-standard tool; mixed Fabric versions where the LastConfig field is not set.","solutions":["Verify all ordering nodes run a Fabric version that populates OrdererBlockMetadata.LastConfig and upgrade any outdated nodes.","Force a view change / re-proposal so a healthy leader rebuilds the block with complete orderer metadata.","Inspect the offending block's metadata for corruption; restore the ledger from a snapshot if bytes are malformed.","If this occurs during channel creation or genesis processing, regenerate the genesis block with the standard configtxgen tooling instead of custom-built blocks."],"exampleFix":"// before: block built without last-config field\nOrdererBlockMetadata{ConsenterMetadata: md}              // LastConfig nil -> error\n// after: proposer always sets it\nOrdererBlockMetadata{ConsenterMetadata: md, LastConfig: &cb.LastConfig{Index: lastConfigBlockNumber}}","handlingStrategy":"validation","validationCode":"omd := &common.OrdererBlockMetadata{}\nif err := proto.Unmarshal(ordererMDBytes, omd); err != nil { return err }\nif omd.GetLastConfig() == nil {\n    return errors.New(\"OrdererBlockMetadata missing LastConfig\")\n}","typeGuard":null,"tryCatchPattern":"if err := verifyProposal(prop); err != nil {\n    if strings.Contains(err.Error(), \"last config is nil\") {\n        // drop proposal, request re-proposal / view change\n    }\n    return err\n}","preventionTips":["Never hand-craft blocks; use standard Fabric block-building code paths","Keep orderer versions homogeneous across the consenter set","Validate block metadata completeness after any crash-recovery"],"tags":["hyperledger-fabric","smartbft","last-config","block-metadata"],"backgroundTag":"missing-block-metadata-field","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"}