{"record":{"id":"fbeb2502b7e5419f","repo":"hyperledger/fabric","slug":"invalid-bft-consenter-mapping-configuration","errorCode":null,"errorMessage":"invalid BFT consenter mapping configuration","messagePattern":"invalid BFT consenter mapping configuration","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/common/msgprocessor/maintenancefilter.go","lineNumber":150,"sourceCode":"\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() {\n\t\tlogger.Infof(\"[channel: %s] maintenance mode: ConsensusType.State about to change from %s to %s\",\n\t\t\tmf.support.ChannelID(), ordererConfig.ConsensusState(), nextOrdererConfig.ConsensusState())\n\t}\n\n\treturn nil\n}\n\n// ensureConsensusTypeChangeOnly checks that the only change is the Channel/Orderer group, and within that,\n// only to the ConsensusType value.\nfunc (mf *MaintenanceFilter) ensureConsensusTypeChangeOnly(configEnvelope *cb.ConfigEnvelope) error {","sourceCodeStart":132,"sourceCodeEnd":168,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/common/msgprocessor/maintenancefilter.go#L132-L168","documentation":"Wraps an error from validateBFTConsenterMapping during a maintenance-mode migration to BFT. The consenter set in the next config's BFT metadata must correspond exactly to the ordering service endpoints/tls certs in the new orderer group configuration; a mismatch is rejected.","triggerScenarios":"Migrating to BFT where the Consenters list in smartbft metadata (host, port, client/server TLS certs) does not match the orderer nodes defined in the new config's Orderer group.","commonSituations":"Adding or removing an orderer node in the same update as the type change, stale TLS certificates in the consenters list, or endpoints copied from a different channel/environment.","solutions":["Regenerate the BFT metadata Consenters so each entry exactly matches an orderer's host, port, and TLS certificates in the next config","Review the wrapped inner error from validateBFTConsenterMapping for the specific mismatched consenter","Update TLS certs on the orderers first (separate maintenance update), then perform the type migration with matching consenter entries"],"exampleFix":"// before: consenter endpoint stale\n{\"Host\": \"orderer-old.example.com\", \"Port\": 7050}\n// after: matches next config orderer\n{\"Host\": \"orderer1.example.com\", \"Port\": 7050}","handlingStrategy":"validation","validationCode":"// ensure every consenter matches an orderer endpoint/tls cert in the next config\nfor _, c := range opts.Consenters {\n    if !ordererInNextConfig(next, c.Host, c.Port, c.ServerTlsCert, c.ClientTlsCert) {\n        return fmt.Errorf(\"consenter %s:%d not present in next orderer config\", c.Host, c.Port)\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Regenerate consenters from the next config's orderer endpoints and TLS certs at migration time","Rotate TLS certificates before entering maintenance, not during the type-change update","Keep the consenter list 1:1 with the orderer nodes defined in the channel"],"tags":["hyperledger-fabric","orderer","smartbft","consenter-mapping","tls"],"backgroundTag":"bft-consenter-mapping-mismatch","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"}