{"record":{"id":"af3132420e342a00","repo":"hyperledger/fabric","slug":"no-suitable-bft-consenter-for-raft-consenter-v","errorCode":null,"errorMessage":"No suitable BFT consenter for Raft consenter: %v","messagePattern":"No suitable BFT consenter for Raft consenter: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/common/msgprocessor/maintenancefilter.go","lineNumber":240,"sourceCode":"\t\treturn errors.Errorf(\"Invalid new config: bft consenters are missing\")\n\t}\n\n\tif len(raftConsenters) != len(bftConsenters) {\n\t\treturn errors.Errorf(\"Invalid new config: the number of bft consenters: %d is not equal to the number of raft consenters: %d\", len(bftConsenters), len(raftConsenters))\n\t}\n\n\tfor _, raftConsenter := range raftConsenters {\n\t\tflag := false\n\t\tfor _, bftConsenter := range bftConsenters {\n\t\t\tif raftConsenter.Port == bftConsenter.Port && raftConsenter.Host == bftConsenter.Host &&\n\t\t\t\tbytes.Equal(raftConsenter.ServerTlsCert, bftConsenter.ServerTlsCert) &&\n\t\t\t\tbytes.Equal(raftConsenter.ClientTlsCert, bftConsenter.ClientTlsCert) {\n\t\t\t\tflag = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif !flag {\n\t\t\treturn errors.Errorf(\"No suitable BFT consenter for Raft consenter: %v\", raftConsenter)\n\t\t}\n\t}\n\n\treturn nil\n}\n","sourceCodeStart":222,"sourceCodeEnd":246,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/common/msgprocessor/maintenancefilter.go#L222-L246","documentation":"After count-checking, each Raft consenter must have a matching BFT consenter identified by identical Host, Port, and TLS certificates. If some Raft consenter has no corresponding BFT entry, the migration is rejected because node identities must be preserved across the consensus-type change.","triggerScenarios":"validateBFTConsenterMapping iterates raftConsenters and finds one whose (Host, Port, ClientTlsCert) tuple does not match any entry in the proposed BFT consenters list — even if the counts are equal.","commonSituations":"Rotating TLS certificates as part of the migration update (certs must match the current Raft certs at migration time); typos in hostnames or ports; reordering entries while a cert pair is mismatched.","solutions":["Ensure each BFT consenter entry has the exact same Host, Port, and ClientTlsCert bytes as the corresponding Raft consenter.","Defer TLS certificate rotation to a separate config update after migration completes.","Regenerate the BFT metadata by copying the Raft consenter list verbatim and only changing the consensus type fields."],"exampleFix":"// before\n// bft consenter: {Host: \"node1.example.com\", Port: 7050, ClientTlsCert: newCert}\n// after\n// bft consenter: {Host: \"node1.example.com\", Port: 7050, ClientTlsCert: raftClientCert}","handlingStrategy":"validation","validationCode":"for _, r := range raftConsenters {\n    found := false\n    for _, b := range bftConsenters {\n        if r.Host == b.Host && r.Port == b.Port && bytes.Equal(r.ClientTlsCert, b.ClientTlsCert) {\n            found = true\n            break\n        }\n    }\n    if !found {\n        return fmt.Errorf(\"no matching BFT consenter for %s:%d\", r.Host, r.Port)\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Copy Raft consenter entries verbatim into the BFT metadata.","Defer TLS cert rotation to a post-migration update.","Byte-compare certificates (not PEM strings) when validating the mapping."],"tags":["hyperledger-fabric","raft","bft","tls"],"backgroundTag":"consenter-config-invalid","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"}