hyperledger/fabric · error
cannot marshal metadata for orderer type %s: %s
Error message
cannot marshal metadata for orderer type %s: %s
What it means
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.
Source
Thrown at internal/configtxgen/encoder/encoder.go:216
conf.BatchSize.MaxMessageCount,
conf.BatchSize.AbsoluteMaxBytes,
conf.BatchSize.PreferredMaxBytes,
), channelconfig.AdminsPolicyKey)
addValue(ordererGroup, channelconfig.BatchTimeoutValue(conf.BatchTimeout.String()), channelconfig.AdminsPolicyKey)
addValue(ordererGroup, channelconfig.ChannelRestrictionsValue(conf.MaxChannels), channelconfig.AdminsPolicyKey)
if len(conf.Capabilities) > 0 {
addValue(ordererGroup, channelconfig.CapabilitiesValue(conf.Capabilities), channelconfig.AdminsPolicyKey)
}
var consensusMetadata []byte
var err error
switch conf.OrdererType {
case ConsensusTypeSolo:
case ConsensusTypeEtcdRaft:
if consensusMetadata, err = channelconfig.MarshalEtcdRaftMetadata(conf.EtcdRaft); err != nil {
return nil, errors.Errorf("cannot marshal metadata for orderer type %s: %s", ConsensusTypeEtcdRaft, err)
}
case ConsensusTypeBFT:
consenterProtos, err := consenterProtosFromConfig(conf.ConsenterMapping)
if err != nil {
return nil, errors.Errorf("cannot load consenter config for orderer type %s: %s", ConsensusTypeBFT, err)
}
addValue(ordererGroup, channelconfig.OrderersValue(consenterProtos), channelconfig.AdminsPolicyKey)
if consensusMetadata, err = channelconfig.MarshalBFTOptions(conf.SmartBFT); err != nil {
return nil, errors.Errorf("consenter options read failed with error %s for orderer type %s", err, ConsensusTypeBFT)
}
// Force leader rotation to be turned off
conf.SmartBFT.LeaderRotation = smartbft.Options_ROTATION_OFF
// Overwrite policy manually by computing it from the consenters
policies.EncodeBFTBlockVerificationPolicy(consenterProtos, ordererGroup)
default:
return nil, errors.Errorf("unknown orderer type: %s", conf.OrdererType)
}
View on GitHub (pinned to 2736b63f8f)
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
Example fix
# before
EtcdRaft:
Consenters:
- Host: orderer.example.com
Port: 7050
# missing certs
# after
EtcdRaft:
Consenters:
- Host: orderer.example.com
Port: 7050
ClientTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.crt
ServerTLSCert: crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.crt Defensive patterns
Strategy: validation
Validate before calling
func validateEtcdRaft(conf *genesisconfig.EtcdRaft) error {
if len(conf.Consenters) == 0 { return errors.New("etcdraft requires at least one consenter") }
for _, c := range conf.Consenters {
if _, err := os.ReadFile(c.ClientTLSCert); err != nil { return fmt.Errorf("client cert: %w", err) }
if _, err := os.ReadFile(c.ServerTLSCert); err != nil { return fmt.Errorf("server cert: %w", err) }
}
return nil
} Type guard
func isEtcdRaft(conf *genesisconfig.Orderer) bool { return conf.OrdererType == "etcdraft" } Try / catch
group, err := encoder.NewOrdererGroup(conf, caps)
if err != nil {
if strings.Contains(err.Error(), "cannot marshal metadata") {
return fmt.Errorf("fix EtcdRaft section (consenters/certs/ticks): %w", err)
}
return err
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- could not read config update
- nil Raft config metadata options
- none of HeartbeatTick (%d), ElectionTick (%d) and MaxInfligh
- ElectionTick (%d) must be greater than HeartbeatTick (%d)
- failed to parse TickInterval (%s) to time duration: %s
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/11edb98891945948.
Report an issue: GitHub.