{"record":{"id":"ce5f59d14a61aad5","repo":"hyperledger/fabric","slug":"nil-raft-config-metadata","errorCode":null,"errorMessage":"nil Raft config metadata","messagePattern":"nil Raft config metadata","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/consensus/etcdraft/util.go","lineNumber":210,"sourceCode":"\tif err != nil {\n\t\treturn nil, nil, errors.Wrap(err, \"failed to extract payload from config envelope\")\n\t}\n\t// get config update\n\tconfigUpdate, err := configtx.UnmarshalConfigUpdateFromPayload(payload)\n\tif err != nil {\n\t\treturn nil, nil, errors.Wrap(err, \"could not read config update\")\n\t}\n\n\treturn MetadataFromConfigUpdate(configUpdate)\n}\n\n// VerifyConfigMetadata validates Raft config metadata.\n// Note: ignores certificates expiration.\nfunc VerifyConfigMetadata(metadata *etcdraft.ConfigMetadata, verifyOpts x509.VerifyOptions) error {\n\tif metadata == nil {\n\t\t// defensive check. this should not happen as CheckConfigMetadata\n\t\t// should always be called with non-nil config metadata\n\t\treturn errors.Errorf(\"nil Raft config metadata\")\n\t}\n\n\tif metadata.GetOptions() == nil {\n\t\treturn errors.Errorf(\"nil Raft config metadata options\")\n\t}\n\n\tif metadata.GetOptions().GetHeartbeatTick() == 0 ||\n\t\tmetadata.GetOptions().GetElectionTick() == 0 ||\n\t\tmetadata.GetOptions().GetMaxInflightBlocks() == 0 {\n\t\t// if SnapshotIntervalSize is zero, DefaultSnapshotIntervalSize is used\n\t\treturn errors.Errorf(\"none of HeartbeatTick (%d), ElectionTick (%d) and MaxInflightBlocks (%d) can be zero\",\n\t\t\tmetadata.GetOptions().GetHeartbeatTick(), metadata.GetOptions().GetElectionTick(), metadata.GetOptions().GetMaxInflightBlocks())\n\t}\n\n\t// check Raft options\n\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())","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/consensus/etcdraft/util.go#L192-L228","documentation":"VerifyConfigMetadata validates a Raft ConfigMetadata proto. It returns this error when the metadata pointer itself is nil. The comment marks it as defensive: CheckConfigMetadata/metadata construction should never produce a nil ConfigMetadata, so reaching this indicates a programming or decoding failure upstream.","triggerScenarios":"Calling VerifyConfigMetadata(nil, opts) directly, or passing metadata extracted from a config update whose ConsensusType.Metadata failed to decode into etcdraft.ConfigMetadata.","commonSituations":"Unit tests calling with nil; channel config where consensus_type metadata is empty bytes; unmarshalling skipped but nil result propagated.","solutions":["Check that the value passed is a non-nil *etcdraft.ConfigMetadata before calling VerifyConfigMetadata.","Confirm the channel config's ConsensusType.Metadata was unmarshalled into etcdraft.ConfigMetadata (not raw bytes).","If metadata comes from a config update, ensure MetadataFromConfigUpdate succeeded without error."],"exampleFix":"// before\nerr := VerifyConfigMetadata(meta, opts)\n// after\nif meta == nil { return errors.New(\"missing raft config metadata\") }\nerr := VerifyConfigMetadata(meta, opts)","handlingStrategy":"type-guard","validationCode":"if metadata == nil {\n\treturn errors.New(\"raft config metadata not extracted; check ConsensusType in channel config\")\n}","typeGuard":"func hasRaftMetadata(m *etcdraft.ConfigMetadata) bool { return m != nil }","tryCatchPattern":"if err := VerifyConfigMetadata(meta, opts); err != nil {\n\tif strings.Contains(err.Error(), \"nil Raft config metadata\") {\n\t\treturn errors.New(\"metadata missing entirely - not a raft channel?\")\n\t}\n\treturn err\n}","preventionTips":["Never call VerifyConfigMetadata on results of failed metadata extraction.","Check the channel's consensus type is etcdraft before raft-specific validation.","Fail fast when Unmarshal of ConsensusType.Metadata returns nil."],"tags":["hyperledger-fabric","raft","nil-pointer","validation"],"backgroundTag":"nil-raft-config-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"}