{"record":{"id":"922d082b229a7298","repo":"hyperledger/fabric","slug":"failed-to-unmarshal-consensus-metadata-922d08","errorCode":null,"errorMessage":"failed to unmarshal consensus metadata","messagePattern":"failed to unmarshal consensus metadata","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/consensus/smartbft/util.go","lineNumber":457,"sourceCode":"\t}\n\n\tif len(w.work) == 0 {\n\t\tpanic(\"work is not defined\")\n\t}\n\n\tfor i, datum := range w.work {\n\t\tif i%w.workerNum != w.id {\n\t\t\tcontinue\n\t\t}\n\n\t\tw.f(datum)\n\t}\n}\n\nfunc createSmartBftConfig(ordererConfig channelconfig.Orderer) (*smartbft.Options, error) {\n\tconfigOptions := &smartbft.Options{}\n\tif err := proto.Unmarshal(ordererConfig.ConsensusMetadata(), configOptions); err != nil {\n\t\treturn nil, errors.Wrap(err, \"failed to unmarshal consensus metadata\")\n\t}\n\tbatchSize := ordererConfig.BatchSize()\n\tconfigOptions.RequestBatchMaxCount = uint64(batchSize.MaxMessageCount)\n\tconfigOptions.RequestBatchMaxBytes = uint64(batchSize.AbsoluteMaxBytes)\n\treturn configOptions, nil\n}\n\n// ledgerInfoAdapter translates from blocksprovider.LedgerInfo in to calls to consensus.ConsenterSupport.\ntype ledgerInfoAdapter struct {\n\tsupport consensus.ConsenterSupport\n}\n\nfunc (a *ledgerInfoAdapter) LedgerHeight() (uint64, error) {\n\treturn a.support.Height(), nil\n}\n\nfunc (a *ledgerInfoAdapter) GetCurrentBlockHash() ([]byte, error) {\n\treturn nil, errors.New(\"not implemented: never used in orderer\")","sourceCodeStart":439,"sourceCodeEnd":475,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/consensus/smartbft/util.go#L439-L475","documentation":"createSmartBftConfig reads the Orderer config group's consensus metadata and unmarshals it into smartbft.Options. If the metadata bytes are not a valid protobuf encoding of the expected options message, proto.Unmarshal fails and the error is wrapped with this message.","triggerScenarios":"A config block whose Orderer/ConsensusType metadata is empty, truncated, or encoded for a different consensus type (e.g. etcdraft metadata) being processed by HandleChain / configBlockToBFTConfig.","commonSituations":"Committing a channel config update with wrong or missing consensus metadata; hand-editing config blocks; migrating a channel to BFT without populating BFT options metadata.","solutions":["Regenerate the config block with correct BFT consensus metadata built by configtxgen/configtxlator","Use configtxlator to update the consensus_metadata field with a properly encoded smartbft proto instead of hand editing","Re-commit a config update that sets valid SmartBFT options (window size, batch timeout, etc.)"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"md := ordererConfig.ConsensusMetadata()\nopts := &smartbft.Options{}\nif err := proto.Unmarshal(md, opts); err != nil {\n    return fmt.Errorf(\"invalid BFT consensus metadata: %w\", err)\n}","typeGuard":"func hasValidBFTMetadata(md []byte) bool {\n    o := &smartbft.Options{}\n    return proto.Unmarshal(md, o) == nil\n}","tryCatchPattern":"if _, err := createSmartBftConfig(ordererConfig); err != nil {\n    if strings.Contains(err.Error(), \"failed to unmarshal consensus metadata\") {\n        // regenerate config block via configtxgen/configtxlator\n    }\n}","preventionTips":["Never hand-edit config block metadata bytes","Use configtxlator to modify consensus_metadata","Regenerate genesis blocks after changing consensus settings"],"tags":["hyperledger-fabric","smartbft","protobuf","config-update"],"backgroundTag":"proto-unmarshal-failed","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"}