{"record":{"id":"7356387c74149b4e","repo":"hyperledger/fabric","slug":"failed-to-unmarshal-updated-new-etcdraft-metadat","errorCode":null,"errorMessage":"failed to unmarshal updated (new) etcdraft metadata configuration","messagePattern":"failed to unmarshal updated \\(new\\) etcdraft metadata configuration","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/consensus/etcdraft/util.go","lineNumber":101,"sourceCode":"\t}\n\treturn nil\n}\n\n// MetadataFromConfigValue reads and translates configuration updates from config value into raft metadata\n// In case consensus type is changed to BFT the raft metadata will be nil\nfunc MetadataFromConfigValue(configValue *common.ConfigValue) (*etcdraft.ConfigMetadata, *orderer.ConsensusType, error) {\n\tconsensusTypeValue := &orderer.ConsensusType{}\n\tif err := proto.Unmarshal(configValue.GetValue(), consensusTypeValue); err != nil {\n\t\treturn nil, nil, errors.Wrap(err, \"failed to unmarshal consensusType config update\")\n\t}\n\n\tif consensusTypeValue.GetType() != \"etcdraft\" {\n\t\treturn nil, consensusTypeValue, nil\n\t}\n\n\tupdatedMetadata := &etcdraft.ConfigMetadata{}\n\tif err := proto.Unmarshal(consensusTypeValue.GetMetadata(), updatedMetadata); err != nil {\n\t\treturn nil, nil, errors.Wrap(err, \"failed to unmarshal updated (new) etcdraft metadata configuration\")\n\t}\n\n\treturn updatedMetadata, consensusTypeValue, nil\n}\n\n// MetadataFromConfigUpdate extracts consensus metadata from config update\nfunc MetadataFromConfigUpdate(update *common.ConfigUpdate) (*etcdraft.ConfigMetadata, *orderer.ConsensusType, error) {\n\tvar baseVersion uint64\n\tif update.GetReadSet() != nil && update.ReadSet.Groups != nil {\n\t\tif ordererConfigGroup, ok := update.GetReadSet().GetGroups()[\"Orderer\"]; ok {\n\t\t\tif val, ok := ordererConfigGroup.GetValues()[\"ConsensusType\"]; ok {\n\t\t\t\tbaseVersion = val.GetVersion()\n\t\t\t}\n\t\t}\n\t}\n\n\tif update.GetWriteSet() != nil && update.WriteSet.Groups != nil {\n\t\tif ordererConfigGroup, ok := update.GetWriteSet().GetGroups()[\"Orderer\"]; ok {","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/consensus/etcdraft/util.go#L83-L119","documentation":"After confirming the consensus type is etcdraft, MetadataFromConfigValue unmarshals the metadata field into etcdraft.ConfigMetadata. If proto.Unmarshal fails, the metadata bytes are not a valid ConfigMetadata and the update is rejected with this wrapped error.","triggerScenarios":"A config update of type etcdraft whose consensusType.metadata bytes are empty/corrupt or were produced with an incompatible etcdraft proto schema, failing proto.Unmarshal(consensusTypeValue.GetMetadata(), updatedMetadata).","commonSituations":"Config-update tooling from a different Fabric version emitting an older/newer metadata schema; truncation or manual assembly of the metadata bytes; switching from another consensus type with leftover garbage in the metadata field.","solutions":["Regenerate the metadata with the matching Fabric version's etcdraft proto (e.g. via configtxlator) and resubmit the update","Align the config-generation tooling version with the orderer's Fabric version","Validate the marshaled metadata by round-tripping proto.Unmarshal locally before submitting"],"exampleFix":"// before\nmetadataBytes := []byte(jsonString) // not protobuf\n// after\nmetadataBytes, err := proto.Marshal(&etcdraft.ConfigMetadata{Consenters: consenters})\nif err != nil { return err }","handlingStrategy":"type-guard","validationCode":"// pre-validate metadata bytes before building the update\ncheck := &etcdraft.ConfigMetadata{}\nif err := proto.Unmarshal(metadataBytes, check); err != nil {\n\treturn fmt.Errorf(\"metadata is not valid ConfigMetadata protobuf: %w\", err)\n}","typeGuard":"func isRaftMetadata(b []byte) bool {\n\tmd := &etcdraft.ConfigMetadata{}\n\treturn proto.Unmarshal(b, md) == nil && len(md.GetConsenters()) > 0\n}","tryCatchPattern":"md, ct, err := MetadataFromConfigValue(configValue)\nif err != nil {\n\tif strings.Contains(err.Error(), \"failed to unmarshal updated (new) etcdraft metadata\") {\n\t\treturn fmt.Errorf(\"raft metadata malformed — regenerate with matching Fabric version: %w\", err)\n\t}\n\treturn err\n}","preventionTips":["Serialize metadata with proto.Marshal from the matching Fabric etcdraft package","Never embed JSON or PEM bytes where ConfigMetadata protobuf is expected","Round-trip unmarshal the metadata before submitting the config transaction","Align configtxlator/tooling version with the orderer's Fabric version"],"tags":["raft","config","protobuf","unmarshal","metadata"],"backgroundTag":"protobuf-unmarshal-failed","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"}