{"record":{"id":"fe6a37851e32911f","repo":"hyperledger/fabric","slug":"config-must-contain-a-channel-group","errorCode":null,"errorMessage":"config must contain a channel group","messagePattern":"config must contain a channel group","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"common/channelconfig/bundle.go","lineNumber":239,"sourceCode":"\tconfigtxManager, err := configtx.NewValidatorImpl(channelID, config, RootGroupKey, policyManager)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"initializing configtx manager failed\")\n\t}\n\n\treturn &Bundle{\n\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}","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/common/channelconfig/bundle.go#L221-L257","documentation":"This error means the config transaction submitted to NewBundle had a nil ChannelGroup. preValidate in common/channelconfig/bundle.go runs first on every new bundle and requires a channel-level config group to exist, since all channel configuration (capabilities, orderer/application/consortium sub-groups) hangs off it. Without it there is nothing to validate or build a bundle from.","triggerScenarios":"Calling NewBundle with a *cb.Config whose ChannelGroup field is nil (or passing a config built without a channel group). preValidate is invoked by NewBundle and anonymous bundle-construction paths, so any bundle creation from a truncated or partially decoded ConfigEnvelope hits it.","commonSituations":"Hand-crafted or tool-generated config update payloads that only populate an Application or Orderer group at the top level; configtx.yaml output post-processed incorrectly; a marshaled ConfigEnvelope truncated so ChannelGroup fails to unmarshal; tests constructing cb.Config{} directly without ChannelGroup.","solutions":["Regenerate the config from configtxgen/configtxlator so a ChannelGroup is present at the root of cb.Config","If decoding a ConfigEnvelope, verify the envelope is complete and unmarshals fully (check err from proto.Unmarshal)","In tests, populate cfg.ChannelGroup = &cb.ConfigGroup{} (plus required values) before calling NewBundle","Validate the update with `configtxlator proto_decode` before submitting it to the orderer"],"exampleFix":"// before\ncfg := &cb.Config{Values: map[string]*cb.ConfigValue{}}\nbundle, err := channelconfig.NewBundle(cfg, bccsp) // panics into: config must contain a channel group\n\n// after\ncfg := &cb.Config{\n    ChannelGroup: &cb.ConfigGroup{\n        Values: map[string]*cb.ConfigValue{},\n        Groups: map[string]*cb.ConfigGroup{},\n    },\n}\nbundle, err := channelconfig.NewBundle(cfg, bccsp)","handlingStrategy":"validation","validationCode":"func validChannelConfig(cfg *cb.Config) bool {\n    return cfg != nil && cfg.ChannelGroup != nil\n}\nif !validChannelConfig(cfg) {\n    return fmt.Errorf(\"refusing to build bundle: config has no channel group\")\n}\nbundle, err := channelconfig.NewBundle(cfg, bccsp)","typeGuard":"if cg, ok := cfg.ChannelGroup.(*cb.ConfigGroup); ok && cg != nil { /* safe to use cg */ }","tryCatchPattern":"bundle, err := channelconfig.NewBundle(cfg, bccsp)\nif err != nil && strings.Contains(err.Error(), \"config must contain a channel group\") {\n    // regenerate config / fix construction and retry once\n}","preventionTips":["Always build configs with configtxgen/configtxlator rather than hand-assembling cb.Config","Assert ChannelGroup != nil in unit tests before calling NewBundle","Validate the full ConfigEnvelope unmarshals without error before submission"],"tags":["fabric","channelconfig","config-transaction","protobuf"],"backgroundTag":"missing-required-config-field","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"}