{"record":{"id":"11edb98891945948","repo":"hyperledger/fabric","slug":"cannot-marshal-metadata-for-orderer-type-s-s","errorCode":null,"errorMessage":"cannot marshal metadata for orderer type %s: %s","messagePattern":"cannot marshal metadata for orderer type (.+?): (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/configtxgen/encoder/encoder.go","lineNumber":216,"sourceCode":"\t\tconf.BatchSize.MaxMessageCount,\n\t\tconf.BatchSize.AbsoluteMaxBytes,\n\t\tconf.BatchSize.PreferredMaxBytes,\n\t), channelconfig.AdminsPolicyKey)\n\taddValue(ordererGroup, channelconfig.BatchTimeoutValue(conf.BatchTimeout.String()), channelconfig.AdminsPolicyKey)\n\taddValue(ordererGroup, channelconfig.ChannelRestrictionsValue(conf.MaxChannels), channelconfig.AdminsPolicyKey)\n\n\tif len(conf.Capabilities) > 0 {\n\t\taddValue(ordererGroup, channelconfig.CapabilitiesValue(conf.Capabilities), channelconfig.AdminsPolicyKey)\n\t}\n\n\tvar consensusMetadata []byte\n\tvar err error\n\n\tswitch conf.OrdererType {\n\tcase ConsensusTypeSolo:\n\tcase ConsensusTypeEtcdRaft:\n\t\tif consensusMetadata, err = channelconfig.MarshalEtcdRaftMetadata(conf.EtcdRaft); err != nil {\n\t\t\treturn nil, errors.Errorf(\"cannot marshal metadata for orderer type %s: %s\", ConsensusTypeEtcdRaft, err)\n\t\t}\n\tcase ConsensusTypeBFT:\n\t\tconsenterProtos, err := consenterProtosFromConfig(conf.ConsenterMapping)\n\t\tif err != nil {\n\t\t\treturn nil, errors.Errorf(\"cannot load consenter config for orderer type %s: %s\", ConsensusTypeBFT, err)\n\t\t}\n\t\taddValue(ordererGroup, channelconfig.OrderersValue(consenterProtos), channelconfig.AdminsPolicyKey)\n\t\tif consensusMetadata, err = channelconfig.MarshalBFTOptions(conf.SmartBFT); err != nil {\n\t\t\treturn nil, errors.Errorf(\"consenter options read failed with error %s for orderer type %s\", err, ConsensusTypeBFT)\n\t\t}\n\t\t// Force leader rotation to be turned off\n\t\tconf.SmartBFT.LeaderRotation = smartbft.Options_ROTATION_OFF\n\t\t// Overwrite policy manually by computing it from the consenters\n\t\tpolicies.EncodeBFTBlockVerificationPolicy(consenterProtos, ordererGroup)\n\tdefault:\n\t\treturn nil, errors.Errorf(\"unknown orderer type: %s\", conf.OrdererType)\n\t}\n","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/internal/configtxgen/encoder/encoder.go#L198-L234","documentation":"For etcdraft orderers, NewOrdererGroup serializes conf.EtcdRaft (consenters, tick interval, election/heartbeat timeouts) into the config group metadata via channelconfig.MarshalEtcdRaftMetadata. If that proto cannot be marshaled or validated, the encoder fails with this message naming the etcdraft orderer type and the underlying error.","triggerScenarios":"Calling NewOrdererGroup/NewChannelGroup with OrdererType \"etcdraft\" where conf.EtcdRaft is invalid — e.g. malformed TLS cert paths/contents in Consenters, unset required fields — causing MarshalEtcdRaftMetadata to error.","commonSituations":"TLS certificate paths in EtcdRaft.Consenters pointing to files that are unreadable or not valid PEM, empty Consenters list, or programmatically constructed genesisconfig with a nil/zero EtcdRaft struct.","solutions":["Check the underlying error after the colon — it identifies which field failed validation","Verify every consenter's ClientTLSCert/ServerTLSCert paths exist and contain valid PEM","Ensure EtcdRaft settings (TickInterval, ElectionTick, HeartbeatTick, MaxInflightBlocks) are set per the sample configtx.yaml","Regenerate the genesis block after fixing the EtcdRaft section"],"exampleFix":"# before\nEtcdRaft:\n    Consenters:\n        - Host: orderer.example.com\n          Port: 7050\n          # missing certs\n# after\nEtcdRaft:\n    Consenters:\n        - Host: orderer.example.com\n          Port: 7050\n          ClientTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.crt\n          ServerTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.crt","handlingStrategy":"validation","validationCode":"func validateEtcdRaft(conf *genesisconfig.EtcdRaft) error {\n    if len(conf.Consenters) == 0 { return errors.New(\"etcdraft requires at least one consenter\") }\n    for _, c := range conf.Consenters {\n        if _, err := os.ReadFile(c.ClientTLSCert); err != nil { return fmt.Errorf(\"client cert: %w\", err) }\n        if _, err := os.ReadFile(c.ServerTLSCert); err != nil { return fmt.Errorf(\"server cert: %w\", err) }\n    }\n    return nil\n}","typeGuard":"func isEtcdRaft(conf *genesisconfig.Orderer) bool { return conf.OrdererType == \"etcdraft\" }","tryCatchPattern":"group, err := encoder.NewOrdererGroup(conf, caps)\nif err != nil {\n    if strings.Contains(err.Error(), \"cannot marshal metadata\") {\n        return fmt.Errorf(\"fix EtcdRaft section (consenters/certs/ticks): %w\", err)\n    }\n    return err\n}","preventionTips":["Keep EtcdRaft fields exactly as in the official sample configtx.yaml","Point cert paths at generated crypto material and use absolute paths in CI","Test profile generation with configtxgen after any EtcdRaft edit"],"tags":["config","hyperledger-fabric","raft","serialization"],"backgroundTag":"consensus-metadata-marshal-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"}