hyperledger/fabric · critical
Invalid new config: bft consenters are missing
Error message
Invalid new config: bft consenters are missing
What it means
validateBFTConsenterMapping checks the next (proposed) orderer config when migrating from Raft (etcdraft) to BFT consensus. The new config must list at least one BFT consenter; an empty consenter set means the resulting channel would have no orderers and cannot function, so it is rejected outright.
Source
Thrown at orderer/common/msgprocessor/maintenancefilter.go:222
}
} else {
return errors.Errorf("update does not contain the %s group", channelconfig.OrdererGroupKey)
}
return nil
}
func validateBFTConsenterMapping(currentOrdererConfig channelconfig.Orderer, nextOrdererConfig channelconfig.Orderer) error {
// extract raft consenters from consensusTypeValue.metadata
raftMetadata := &etcdraft.ConfigMetadata{}
proto.Unmarshal(currentOrdererConfig.ConsensusMetadata(), raftMetadata)
raftConsenters := raftMetadata.GetConsenters()
// extract bft consenters
bftConsenters := nextOrdererConfig.Consenters()
if len(bftConsenters) == 0 {
return errors.Errorf("Invalid new config: bft consenters are missing")
}
if len(raftConsenters) != len(bftConsenters) {
return 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))
}
for _, raftConsenter := range raftConsenters {
flag := false
for _, bftConsenter := range bftConsenters {
if raftConsenter.Port == bftConsenter.Port && raftConsenter.Host == bftConsenter.Host &&
bytes.Equal(raftConsenter.ServerTlsCert, bftConsenter.ServerTlsCert) &&
bytes.Equal(raftConsenter.ClientTlsCert, bftConsenter.ClientTlsCert) {
flag = true
break
}
}
if !flag {
return errors.Errorf("No suitable BFT consenter for Raft consenter: %v", raftConsenter)View on GitHub (pinned to 2736b63f8f)
Solutions
- Populate the consenters array (host, port, client/server TLS certs) in the new ConsensusType metadata.
- Copy the existing Raft consenters as the starting point for the BFT consenter list, then adjust as needed.
- Validate the marshaled metadata structure with configtxlator before submitting the update.
Example fix
// before
metadata := {"State": "MAINTENANCE", "ConsensusType": "BFT"} // no consenters
// after
metadata := {"ConsensusType": "BFT", "Consenters": [{"Host": "n1", "Port": 7050, ...}]} Defensive patterns
Strategy: validation
Validate before calling
var meta etcdraft.Metadata
protojson.Unmarshal(nextConsensusTypeValue, &meta)
if len(meta.GetConsenters()) == 0 {
return errors.New("new consensus metadata must include consenters")
} Prevention
- Seed the BFT metadata consenters from the existing Raft consenters list.
- Validate marshaled metadata with configtxlator before submission.
- Never hand-write consensus metadata from scratch.
When it happens
Trigger: A migration config update whose Orderer group results in nextOrdererConfig.Consenters() returning an empty slice — e.g. the ConsensusType value's new metadata omits the consenters list entirely.
Common situations: Hand-editing the consensus_type metadata via configtxlator and forgetting to carry the consenters array into the new BFT metadata; generating metadata with only type/state but no nodes.
Related errors
- Invalid new config: the number of bft consenters: %d is not
- No suitable BFT consenter for Raft consenter: %v
- illegal orderer config update detected: endpoints of org %s
- no orderer section in config block
- orderer type BFT must be used with V3_0 channel capability:
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/0b2b29b953586b70.
Report an issue: GitHub.