hyperledger/fabric · critical
failed to unmarshal consensus metadata
Error message
failed to unmarshal consensus metadata
What it means
HandleChain (orderer/consensus/etcdraft/consenter.go:122) unmarshals the channel's consensus metadata from the shared config into an etcdraft.ConfigMetadata proto. This error wraps an unmarshal failure, meaning the bytes stored in the channel config's ConsensusType.Metadata are not a valid ConfigMetadata protobuf. The orderer cannot start the raft chain for the channel.
Source
Thrown at orderer/consensus/etcdraft/consenter.go:122
certAsDER, err := pemToDER(cst.GetServerTlsCert(), nodeID, "server", c.Logger)
if err != nil {
return 0, err
}
if crypto.CertificatesWithSamePublicKey(thisNodeCertAsDER, certAsDER) == nil {
return nodeID, nil
}
}
c.Logger.Warning("Could not find", string(c.Cert), "among", serverCertificates)
return 0, cluster.ErrNotInChannel
}
// HandleChain returns a new Chain instance or an error upon failure
func (c *Consenter) HandleChain(support consensus.ConsenterSupport, metadata *common.Metadata) (consensus.Chain, error) {
m := &etcdraft.ConfigMetadata{}
if err := proto.Unmarshal(support.SharedConfig().ConsensusMetadata(), m); err != nil {
return nil, errors.Wrap(err, "failed to unmarshal consensus metadata")
}
if m.GetOptions() == nil {
return nil, errors.New("etcdraft options have not been provided")
}
isMigration := (metadata == nil || len(metadata.GetValue()) == 0) && (support.Height() > 1)
if isMigration {
c.Logger.Debugf("Block metadata is nil at block height=%d, it is consensus-type migration", support.Height())
}
// determine raft replica set mapping for each node to its id
// for newly started chain we need to read and initialize raft
// metadata by creating mapping between conseter and its id.
// In case chain has been restarted we restore raft metadata
// information from the recently committed block meta data
// field.
blockMetadata, err := ReadBlockMetadata(metadata, m)View on GitHub (pinned to 2736b63f8f)
Solutions
- Regenerate the channel config so consensus metadata is a properly marshaled etcdraft.ConfigMetadata protobuf (as configtxgen/configtxlator produce)
- Verify the consensus type is actually etcdraft and the metadata type matches it
- Compare metadata bytes against a known-good configtxgen output using configtxlator decode
- Recreate the genesis block and reset the channel if config was hand-crafted
Example fix
// before: embedding JSON in config
Metadata: []byte(`{"Consenters":[...]}`)
// after
m := &etcdraft.ConfigMetadata{...}
Metadata, _ := proto.Marshal(m) // configtxgen handles this in Channel.Consensus.Metadata Defensive patterns
Strategy: validation
Validate before calling
m := &etcdraft.ConfigMetadata{}
if err := proto.Unmarshal(sharedConfig.ConsensusMetadata(), m); err != nil {
return fmt.Errorf("channel metadata is not a valid ConfigMetadata proto: %w", err)
} Type guard
func isValidConfigMetadata(raw []byte) bool {
m := &etcdraft.ConfigMetadata{}
return proto.Unmarshal(raw, m) == nil && len(m.GetConsenters()) > 0
} Prevention
- Always generate consensus metadata with configtxgen/configtxlator, never hand-write bytes
- Confirm consensus type matches metadata type
- Decode metadata with configtxlator to sanity-check before channel creation
When it happens
Trigger: Orderer startup or chain creation where support.SharedConfig().ConsensusMetadata() returns bytes that fail proto.Unmarshal into etcdraft.ConfigMetadata.
Common situations: Channel created with consensus metadata left as raw JSON or empty/garbage bytes instead of marshaled ConfigMetadata; a migration or config edit wrote the wrong protobuf type; tooling that JSON-encoded the metadata instead of protobuf-marshaling it.
Related errors
- failed to unmarshal updated (new) etcdraft metadata configur
- invalid new config metadata
- etcdraft options have not been provided
- failed to read Raft metadata
- nil metadata
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/02e541c2156154dc.
Report an issue: GitHub.