{"record":{"id":"e6424ddc3e058500","repo":"hyperledger/fabric","slug":"empty-config","errorCode":null,"errorMessage":"empty Config","messagePattern":"empty Config","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/consensus/smartbft/configverifier.go","lineNumber":96,"sourceCode":"\tif err != nil {\n\t\treturn fmt.Errorf(\"channel header unmarshalling error: %s\", err)\n\t}\n\n\tswitch chdr.Type {\n\tcase int32(common.HeaderType_CONFIG):\n\t\tconfigEnvelope := &common.ConfigEnvelope{}\n\t\tif err = proto.Unmarshal(payload.Data, configEnvelope); err != nil {\n\t\t\treturn fmt.Errorf(\"data unmarshalling error: %s\", err)\n\t\t}\n\t\treturn cbv.verifyConfigUpdateMsg(envelope, configEnvelope, chdr)\n\tdefault:\n\t\treturn errors.Errorf(\"unexpected envelope type %s\", common.HeaderType_name[chdr.Type])\n\t}\n}\n\nfunc (cbv *ConfigBlockValidator) checkConsentersMatchPolicy(conf *common.Config) error {\n\tif conf == nil {\n\t\treturn fmt.Errorf(\"empty Config\")\n\t}\n\n\tif conf.ChannelGroup == nil {\n\t\treturn fmt.Errorf(\"empty channel group\")\n\t}\n\n\tif len(conf.ChannelGroup.Groups) == 0 {\n\t\treturn fmt.Errorf(\"no groups in channel group\")\n\t}\n\n\tif conf.ChannelGroup.Groups[\"Orderer\"] == nil {\n\t\treturn fmt.Errorf(\"no 'Orderer' group in channel groups\")\n\t}\n\n\tif len(conf.ChannelGroup.Groups[\"Orderer\"].Values) == 0 {\n\t\treturn fmt.Errorf(\"no values in 'Orderer' group\")\n\t}\n","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/consensus/smartbft/configverifier.go#L78-L114","documentation":"checkConsentersMatchPolicy requires a non-nil *common.Config to inspect the channel's consenter set and BlockValidation policy. A nil Config means the config envelope carried no Config at all, so there is nothing to validate, and the verifier fails fast with 'empty Config'.","triggerScenarios":"Calling ValidateConfig on a CONFIG envelope whose ConfigEnvelope.Config is nil (verifyConfigUpdateMsg passes confEnv.Config straight into checkConsentersMatchPolicy). Note verifyConfigUpdateMsg already rejects confEnv==nil, so this fires when the Config field itself is nil.","commonSituations":"Hand-crafted or corrupted config blocks missing the Config field; deserialization producing an empty ConfigEnvelope; tooling that builds config envelopes programmatically and forgets to populate Config.","solutions":["Ensure the ConfigEnvelope.Config field is populated with the full channel *common.Config before the block is committed/validated","Re-fetch the config block from the ordering service in case the envelope was truncated or corrupted","If constructing the envelope in tests, set LastUpdate and Config explicitly (e.g. via configtx tooling output)"],"exampleFix":"// before\nconfEnv := &common.ConfigEnvelope{LastUpdate: update} // Config is nil\n// after\nconfEnv := &common.ConfigEnvelope{LastUpdate: update, Config: config}","handlingStrategy":"validation","validationCode":"func hasConfig(confEnv *common.ConfigEnvelope) bool {\n  return confEnv != nil && confEnv.Config != nil\n}","typeGuard":"func isPopulatedConfig(c *common.Config) bool { return c != nil }","tryCatchPattern":"if err := cbv.ValidateConfig(envelope); err != nil {\n  if strings.Contains(err.Error(), \"empty Config\") {\n    return fmt.Errorf(\"config block is malformed: %w\", err)\n  }\n  return err\n}","preventionTips":["Always set ConfigEnvelope.Config alongside LastUpdate","Unmarshal config blocks with protoutil.UnmarshalConfigEnvelope rather than manual parsing","Validate generated config with configtxlator before committing"],"tags":["hyperledger-fabric","smartbft","config-validation","nil-config"],"backgroundTag":"empty-configuration","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"}