hyperledger/fabric · error
orderer type BFT must be used with V3_0 channel capability:
Error message
orderer type BFT must be used with V3_0 channel capability: %v
What it means
configtxgen refuses to build a channel/orderer config group when the orderer type is BFT (SmartBFT) but the channel definition does not enable the V3_0 capability. BFT consensus depends on V3_0 channel semantics, so the encoder fails fast at genesis-block/config creation time. The error message includes the full channelCapabilities map so you can see what is enabled.
Source
Thrown at internal/configtxgen/encoder/encoder.go:187
}
if conf.Consortiums != nil {
channelGroup.Groups[channelconfig.ConsortiumsGroupKey], err = NewConsortiumsGroup(conf.Consortiums)
if err != nil {
return nil, errors.Wrap(err, "could not create consortiums group")
}
}
channelGroup.ModPolicy = channelconfig.AdminsPolicyKey
return channelGroup, nil
}
// NewOrdererGroup returns the orderer component of the channel configuration. It defines parameters of the ordering service
// about how large blocks should be, how frequently they should be emitted, etc. as well as the organizations of the ordering network.
// It sets the mod_policy of all elements to "Admins". This group is always present in any channel configuration.
func NewOrdererGroup(conf *genesisconfig.Orderer, channelCapabilities map[string]bool) (*cb.ConfigGroup, error) {
if conf.OrdererType == "BFT" && !channelCapabilities["V3_0"] {
return nil, errors.Errorf("orderer type BFT must be used with V3_0 channel capability: %v", channelCapabilities)
}
if len(conf.Addresses) > 0 && channelCapabilities["V3_0"] {
return nil, errors.Errorf("global orderer endpoints exist, but can not be used with V3_0 capability: %v", conf.Addresses)
}
ordererGroup := protoutil.NewConfigGroup()
if err := AddOrdererPolicies(ordererGroup, conf.Policies, channelconfig.AdminsPolicyKey); err != nil {
return nil, errors.Wrapf(err, "error adding policies to orderer group")
}
addValue(ordererGroup, channelconfig.BatchSizeValue(
conf.BatchSize.MaxMessageCount,
conf.BatchSize.AbsoluteMaxBytes,
conf.BatchSize.PreferredMaxBytes,
), channelconfig.AdminsPolicyKey)
addValue(ordererGroup, channelconfig.BatchTimeoutValue(conf.BatchTimeout.String()), channelconfig.AdminsPolicyKey)
addValue(ordererGroup, channelconfig.ChannelRestrictionsValue(conf.MaxChannels), channelconfig.AdminsPolicyKey)
if len(conf.Capabilities) > 0 {View on GitHub (pinned to 2736b63f8f)
Solutions
- Add V3_0 to Channel.Capabilities in your configtx.yaml profile: Capabilities: Channel: V3_0: {}
- Confirm Orderer.OrdererType is intentionally BFT; if not, revert it to etcdraft (or solo) so V3_0 is not required
- Regenerate the genesis block/channel tx after the capability change: configtxgen -profile <profile> -outputBlock genesis.block
Example fix
# before
Capabilities:
Channel: &ChannelCapabilities
V2_0: true
Orderer:
OrdererType: BFT
# after
Capabilities:
Channel: &ChannelCapabilities
V2_0: true
V3_0: true
Orderer:
OrdererType: BFT Defensive patterns
Strategy: validation
Validate before calling
// Go: validate before calling encoder.NewOrdererGroup
func validateBFTCapability(conf *genesisconfig.Orderer, caps map[string]bool) error {
if conf.OrdererType == "BFT" && !caps["V3_0"] {
return fmt.Errorf("BFT orderer requires V3_0 channel capability; got %v", caps)
}
return nil
} Type guard
func isBFT(conf *genesisconfig.Orderer) bool { return conf.OrdererType == "BFT" }
// usage: if isBFT(conf) && !channelCapabilities["V3_0"] { /* fix caps first */ } Try / catch
group, err := encoder.NewOrdererGroup(conf, caps)
if err != nil {
if strings.Contains(err.Error(), "must be used with V3_0") {
return fmt.Errorf("profile misconfiguration: enable V3_0 channel capability in configtx.yaml: %w", err)
}
return err
} Prevention
- Always pair OrdererType: BFT with Channel.Capabilities V3_0 in the same profile
- Copy capability blocks only from the sample configtx.yaml matching your Fabric version
- Run configtxgen on profiles in CI so capability mismatches fail before deployment
When it happens
Trigger: Calling encoder.NewOrdererGroup (directly or via NewChannelNewConfig/NewChannelGroup from configtxgen OutputBlock/CreateChannelTx) with conf.OrdererType == "BFT" in configtx.yaml while channel Capabilities does not include the "V3_0" key.
Common situations: Developers switch Orderer.OrdererType from etcdraft to BFT in an existing configtx.yaml that still carries an older capabilities set (e.g. V2_0), or copy a BFT sample profile without adding V3_0 to Channel.Capabilities.
Related errors
- global orderer endpoints exist, but can not be used with V3_
- cannot load consenter config for orderer type %s: %s
- consenter options read failed with error %s for orderer type
- organization %s not found
- %s capability %s is required but not supported
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/f0eb4fb9bfa4f5f5.
Report an issue: GitHub.