{"record":{"id":"4e8428f9b6c2e2d8","repo":"hyperledger/fabric","slug":"metadata-has-nil-consenter","errorCode":null,"errorMessage":"metadata has nil consenter","messagePattern":"metadata has nil consenter","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/consensus/etcdraft/util.go","lineNumber":244,"sourceCode":"\tif metadata.GetOptions().GetElectionTick() <= metadata.GetOptions().GetHeartbeatTick() {\n\t\treturn errors.Errorf(\"ElectionTick (%d) must be greater than HeartbeatTick (%d)\",\n\t\t\tmetadata.GetOptions().GetElectionTick(), metadata.GetOptions().GetHeartbeatTick())\n\t}\n\n\tif d, err := time.ParseDuration(metadata.GetOptions().GetTickInterval()); err != nil {\n\t\treturn errors.Errorf(\"failed to parse TickInterval (%s) to time duration: %s\", metadata.GetOptions().GetTickInterval(), err)\n\t} else if d == 0 {\n\t\treturn errors.Errorf(\"TickInterval cannot be zero\")\n\t}\n\n\tif len(metadata.GetConsenters()) == 0 {\n\t\treturn errors.Errorf(\"empty consenter set\")\n\t}\n\n\t// verifying certificates for being signed by CA, expiration is ignored\n\tfor _, consenter := range metadata.GetConsenters() {\n\t\tif consenter == nil {\n\t\t\treturn errors.Errorf(\"metadata has nil consenter\")\n\t\t}\n\t\tif err := validateConsenterTLSCerts(consenter, verifyOpts, true); err != nil {\n\t\t\treturn errors.WithMessagef(err, \"consenter %s:%d has invalid certificate\", consenter.GetHost(), consenter.GetPort())\n\t\t}\n\t}\n\n\tif err := MetadataHasDuplication(metadata); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc parseCertificateFromBytes(cert []byte) (*x509.Certificate, error) {\n\tpemBlock, _ := pem.Decode(cert)\n\tif pemBlock == nil {\n\t\treturn &x509.Certificate{}, errors.Errorf(\"no PEM data found in cert[% x]\", cert)\n\t}","sourceCodeStart":226,"sourceCodeEnd":262,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/consensus/etcdraft/util.go#L226-L262","documentation":"While iterating over the consenters, a nil entry in metadata.GetConsenters() is rejected: every consenter must carry host, port and TLS certs. This indicates malformed metadata rather than an invalid certificate (that produces a different wrapped error).","triggerScenarios":"A ConfigMetadata whose Consenters slice contains a nil element, typically from buggy config-generation code or partial protobuf decoding.","commonSituations":"Programmatically appending consenters and appending a nil pointer; proto decoded with a consenter message that is present but empty and represented as nil in the slice.","solutions":["Remove nil entries and populate each Consenter with Host, Port, ServerTlsCert and ClientTlsCert.","Check the code path that builds Consenters for accidental nil appends.","Pre-validate the slice with a loop checking each element non-nil before calling VerifyConfigMetadata."],"exampleFix":"// before\nconsenters = append(consenters, nilConsenterMaybe())\n// after\nif c := buildConsenter(); c != nil { consenters = append(consenters, c) }","handlingStrategy":"type-guard","validationCode":"for i, c := range metadata.GetConsenters() {\n\tif c == nil {\n\t\treturn fmt.Errorf(\"consenter at index %d is nil\", i)\n\t}\n}","typeGuard":"func allConsentersPresent(m *etcdraft.ConfigMetadata) bool {\n\tfor _, c := range m.GetConsenters() {\n\t\tif c == nil || c.GetHost() == \"\" || c.GetPort() == 0 {\n\t\t\treturn false\n\t\t}\n\t}\n\treturn len(m.GetConsenters()) > 0\n}","tryCatchPattern":"if err := VerifyConfigMetadata(meta, opts); err != nil {\n\tif strings.Contains(err.Error(), \"nil consenter\") {\n\t\treturn errors.New(\"config-generation bug: nil entry in Consenters list\")\n\t}\n\treturn err\n}","preventionTips":["Check for nil before appending to Consenters in generated code.","Add unit tests asserting no nil elements in built ConfigMetadata.","Validate host/port/certs are set on every consenter before submission."],"tags":["hyperledger-fabric","raft","nil-pointer","consenters"],"backgroundTag":"nil-consenter-in-metadata","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"}