{"record":{"id":"dae061b69c78cfc1","repo":"hyperledger/fabric","slug":"cannot-enable-channel-capabilities-without-orderer","errorCode":null,"errorMessage":"cannot enable channel capabilities without orderer support first","messagePattern":"cannot enable channel capabilities without orderer support first","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"common/channelconfig/bundle.go","lineNumber":245,"sourceCode":"\t\tpolicyManager:   policyManager,\n\t\tchannelConfig:   channelConfig,\n\t\tconfigtxManager: configtxManager,\n\t}, nil\n}\n\nfunc preValidate(config *cb.Config) error {\n\tif config == nil {\n\t\treturn errors.New(\"channelconfig Config cannot be nil\")\n\t}\n\n\tif config.ChannelGroup == nil {\n\t\treturn errors.New(\"config must contain a channel group\")\n\t}\n\n\tif og, ok := config.ChannelGroup.Groups[OrdererGroupKey]; ok {\n\t\tif _, ok := og.Values[CapabilitiesKey]; !ok {\n\t\t\tif _, ok := config.ChannelGroup.Values[CapabilitiesKey]; ok {\n\t\t\t\treturn errors.New(\"cannot enable channel capabilities without orderer support first\")\n\t\t\t}\n\n\t\t\tif ag, ok := config.ChannelGroup.Groups[ApplicationGroupKey]; ok {\n\t\t\t\tif _, ok := ag.Values[CapabilitiesKey]; ok {\n\t\t\t\t\treturn errors.New(\"cannot enable application capabilities without orderer support first\")\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n","sourceCodeStart":227,"sourceCodeEnd":258,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/common/channelconfig/bundle.go#L227-L258","documentation":"Fabric enforces a strict capability upgrade ordering: orderer nodes must first support a capability before channel-level capabilities that require it can be enabled. preValidate rejects any config that sets ChannelGroup.Values[CapabilitiesKey] while the Orderer group lacks a Capabilities value. This prevents orderers running older binaries from being handed config they cannot process.","triggerScenarios":"Submitting a channel config update that adds a capability (e.g. V2_0) to the channel group when config.ChannelGroup.Groups[OrdererGroupKey].Values has no CapabilitiesKey entry — typically a single-step upgrade attempted via configtxlator or configtxgen.","commonSituations":"Upgrading a network from v1.4 to v2.x and trying to enable channel capabilities in one step; regenerating channel config with an upgraded configtx.yaml capabilities section but forgetting the orderer group; scripts that patch only the channel group in the decoded config.","solutions":["First perform a config update adding the capability only to the Orderer group (and roll out upgraded orderer binaries), then a second update adding it to the channel group","Edit configtx.yaml so Orderer: Capabilities is set to the target version and re-run configtxgen before touching channel capabilities","Use configtxlator to decode the current config, add the capability under groups.Orderer.values, and submit that update first"],"exampleFix":"// before (single-step: channel capability without orderer capability)\nconfig.ChannelGroup.Values[\"Capabilities\"] = &cb.ConfigValue{...} // rejected\n\n// after (two-step; step 1 shown)\nog := config.ChannelGroup.Groups[\"Orderer\"]\nog.Values[\"Capabilities\"] = &cb.ConfigValue{\n    Value: protoutil.MarshalOrPanic(&cb.Capabilities{Capabilities: []string{\"V2_0\"}}),\n}\n// submit; then add the same capability to ChannelGroup.Values","handlingStrategy":"validation","validationCode":"func ordererCapsPresent(cfg *cb.Config) bool {\n    if cfg.ChannelGroup == nil { return false }\n    _, hasChannelCaps := cfg.ChannelGroup.Values[\"Capabilities\"]\n    og, ok := cfg.ChannelGroup.Groups[\"Orderer\"]\n    if !hasChannelCaps { return true }\n    return ok && og.Values != nil && og.Values[\"Capabilities\"] != nil\n}\nif !ordererCapsPresent(cfg) { return errors.New(\"enable orderer capabilities first\") }","typeGuard":null,"tryCatchPattern":"if err := updateChannelConfig(cfg); err != nil {\n    if strings.Contains(err.Error(), \"without orderer support first\") {\n        return fmt.Errorf(\"split into two updates: orderer capability first, then channel capability\")\n    }\n    return err\n}","preventionTips":["Follow Fabric's documented two-step capability upgrade: orderer group first, then channel/application","Keep capabilities sections of configtx.yaml in sync (Orderer, Channel, Application)","After orderer binary upgrades, immediately push the matching orderer-group capability"],"tags":["fabric","channelconfig","capabilities","upgrade","orderer"],"backgroundTag":"capability-order-violation","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"}