{"record":{"id":"f0eb4fb9bfa4f5f5","repo":"hyperledger/fabric","slug":"orderer-type-bft-must-be-used-with-v3-0-channel-ca","errorCode":null,"errorMessage":"orderer type BFT must be used with V3_0 channel capability: %v","messagePattern":"orderer type BFT must be used with V3_0 channel capability: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/configtxgen/encoder/encoder.go","lineNumber":187,"sourceCode":"\t}\n\n\tif conf.Consortiums != nil {\n\t\tchannelGroup.Groups[channelconfig.ConsortiumsGroupKey], err = NewConsortiumsGroup(conf.Consortiums)\n\t\tif err != nil {\n\t\t\treturn nil, errors.Wrap(err, \"could not create consortiums group\")\n\t\t}\n\t}\n\n\tchannelGroup.ModPolicy = channelconfig.AdminsPolicyKey\n\treturn channelGroup, nil\n}\n\n// NewOrdererGroup returns the orderer component of the channel configuration.  It defines parameters of the ordering service\n// about how large blocks should be, how frequently they should be emitted, etc. as well as the organizations of the ordering network.\n// It sets the mod_policy of all elements to \"Admins\".  This group is always present in any channel configuration.\nfunc NewOrdererGroup(conf *genesisconfig.Orderer, channelCapabilities map[string]bool) (*cb.ConfigGroup, error) {\n\tif conf.OrdererType == \"BFT\" && !channelCapabilities[\"V3_0\"] {\n\t\treturn nil, errors.Errorf(\"orderer type BFT must be used with V3_0 channel capability: %v\", channelCapabilities)\n\t}\n\tif len(conf.Addresses) > 0 && channelCapabilities[\"V3_0\"] {\n\t\treturn nil, errors.Errorf(\"global orderer endpoints exist, but can not be used with V3_0 capability: %v\", conf.Addresses)\n\t}\n\n\tordererGroup := protoutil.NewConfigGroup()\n\tif err := AddOrdererPolicies(ordererGroup, conf.Policies, channelconfig.AdminsPolicyKey); err != nil {\n\t\treturn nil, errors.Wrapf(err, \"error adding policies to orderer group\")\n\t}\n\taddValue(ordererGroup, channelconfig.BatchSizeValue(\n\t\tconf.BatchSize.MaxMessageCount,\n\t\tconf.BatchSize.AbsoluteMaxBytes,\n\t\tconf.BatchSize.PreferredMaxBytes,\n\t), channelconfig.AdminsPolicyKey)\n\taddValue(ordererGroup, channelconfig.BatchTimeoutValue(conf.BatchTimeout.String()), channelconfig.AdminsPolicyKey)\n\taddValue(ordererGroup, channelconfig.ChannelRestrictionsValue(conf.MaxChannels), channelconfig.AdminsPolicyKey)\n\n\tif len(conf.Capabilities) > 0 {","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/internal/configtxgen/encoder/encoder.go#L169-L205","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before\nCapabilities:\n    Channel: &ChannelCapabilities\n        V2_0: true\nOrderer:\n    OrdererType: BFT\n# after\nCapabilities:\n    Channel: &ChannelCapabilities\n        V2_0: true\n        V3_0: true\nOrderer:\n    OrdererType: BFT","handlingStrategy":"validation","validationCode":"// Go: validate before calling encoder.NewOrdererGroup\nfunc validateBFTCapability(conf *genesisconfig.Orderer, caps map[string]bool) error {\n    if conf.OrdererType == \"BFT\" && !caps[\"V3_0\"] {\n        return fmt.Errorf(\"BFT orderer requires V3_0 channel capability; got %v\", caps)\n    }\n    return nil\n}","typeGuard":"func isBFT(conf *genesisconfig.Orderer) bool { return conf.OrdererType == \"BFT\" }\n// usage: if isBFT(conf) && !channelCapabilities[\"V3_0\"] { /* fix caps first */ }","tryCatchPattern":"group, err := encoder.NewOrdererGroup(conf, caps)\nif err != nil {\n    if strings.Contains(err.Error(), \"must be used with V3_0\") {\n        return fmt.Errorf(\"profile misconfiguration: enable V3_0 channel capability in configtx.yaml: %w\", err)\n    }\n    return err\n}","preventionTips":["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"],"tags":["config","hyperledger-fabric","capabilities","bft"],"backgroundTag":"channel-capability-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"}