{"record":{"id":"f47cff2da21a3831","repo":"hyperledger/fabric","slug":"failed-to-unmarshal-bft-metadata-configuration","errorCode":null,"errorMessage":"failed to unmarshal BFT metadata configuration","messagePattern":"failed to unmarshal BFT metadata configuration","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/common/msgprocessor/maintenancefilter.go","lineNumber":140,"sourceCode":"\tif ordererConfig.ConsensusType() != nextOrdererConfig.ConsensusType() {\n\t\tif ordererConfig.ConsensusState() == orderer.ConsensusType_STATE_NORMAL {\n\t\t\treturn errors.Errorf(\"attempted to change consensus type from %s to %s, but current config ConsensusType.State is not in maintenance mode\",\n\t\t\t\tordererConfig.ConsensusType(), nextOrdererConfig.ConsensusType())\n\t\t}\n\t\tif nextOrdererConfig.ConsensusState() == orderer.ConsensusType_STATE_NORMAL {\n\t\t\treturn errors.Errorf(\"attempted to change consensus type from %s to %s, but next config ConsensusType.State is not in maintenance mode\",\n\t\t\t\tordererConfig.ConsensusType(), nextOrdererConfig.ConsensusType())\n\t\t}\n\n\t\tif !mf.permittedTargetConsensusTypes[nextOrdererConfig.ConsensusType()] {\n\t\t\treturn errors.Errorf(\"attempted to change consensus type from %s to %s, transition not supported\",\n\t\t\t\tordererConfig.ConsensusType(), nextOrdererConfig.ConsensusType())\n\t\t}\n\n\t\tif nextOrdererConfig.ConsensusType() == \"BFT\" {\n\t\t\tupdatedMetadata := &smartbft.Options{}\n\t\t\tif err := proto.Unmarshal(nextOrdererConfig.ConsensusMetadata(), updatedMetadata); err != nil {\n\t\t\t\treturn errors.Wrap(err, \"failed to unmarshal BFT metadata configuration\")\n\t\t\t}\n\n\t\t\t_, err := util.ConfigFromMetadataOptions(1, updatedMetadata)\n\t\t\tif err != nil {\n\t\t\t\treturn errors.New(\"invalid BFT metadata configuration\")\n\t\t\t}\n\n\t\t\terr = validateBFTConsenterMapping(ordererConfig, nextOrdererConfig)\n\t\t\tif err != nil {\n\t\t\t\treturn errors.Wrap(err, \"invalid BFT consenter mapping configuration\")\n\t\t\t}\n\t\t}\n\n\t\tlogger.Infof(\"[channel: %s] consensus-type migration: about to change from %s to %s\",\n\t\t\tmf.support.ChannelID(), ordererConfig.ConsensusType(), nextOrdererConfig.ConsensusType())\n\t}\n\n\tif nextOrdererConfig.ConsensusState() != ordererConfig.ConsensusState() {","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/common/msgprocessor/maintenancefilter.go#L122-L158","documentation":"Wraps a protobuf unmarshal failure when the maintenance filter tries to parse the next config's ConsensusMetadata as smartbft.Options during a migration to the BFT consensus type. If the metadata bytes are not a valid protobuf smartbft.Options message, the update is rejected with this wrapped error.","triggerScenarios":"A maintenance-mode config update changing consensus type to \"BFT\" whose ConsensusMetadata field is missing, truncated, or not a valid proto-encoded smartbft.Options message.","commonSituations":"Hand-editing the config JSON with configtxlator and corrupting the metadata (wrong base64, wrong schema, plain JSON pasted where protobuf bytes are expected), or copying metadata from a non-BFT consensus type without regenerating it.","solutions":["Regenerate the BFT ConsensusMetadata as a valid protobuf-encoded smartbft.Options message and base64 it in the config update","Use configtxlator to decode, edit, and re-encode the config instead of hand-crafting bytes","Verify the metadata decodes with protoc --decode=smartbft.Options against the fabric-protos definitions"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Go: verify metadata round-trips as smartbft.Options before submitting\nopts := &smartbft.Options{}\nif err := proto.Unmarshal(metadata, opts); err != nil {\n    return fmt.Errorf(\"BFT metadata invalid: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if err := applyUpdate(env); err != nil {\n    if strings.Contains(err.Error(), \"failed to unmarshal BFT metadata configuration\") {\n        // regenerate metadata with configtxlator and resubmit\n    }\n}","preventionTips":["Always generate BFT metadata via configtxgen/configtxlator, never by hand","Validate the metadata decodes with protoc before embedding it in the update","Beware of base64 corruption when moving config JSON between tools"],"tags":["hyperledger-fabric","orderer","smartbft","protobuf","config-update"],"backgroundTag":"protobuf-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"}