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

  1. Populate the consenters array (host, port, client/server TLS certs) in the new ConsensusType metadata.
  2. Copy the existing Raft consenters as the starting point for the BFT consenter list, then adjust as needed.
  3. 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

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


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/0b2b29b953586b70. Report an issue: GitHub.