{"record":{"id":"02e541c2156154dc","repo":"hyperledger/fabric","slug":"failed-to-unmarshal-consensus-metadata","errorCode":null,"errorMessage":"failed to unmarshal consensus metadata","messagePattern":"failed to unmarshal consensus metadata","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"orderer/consensus/etcdraft/consenter.go","lineNumber":122,"sourceCode":"\t\tcertAsDER, err := pemToDER(cst.GetServerTlsCert(), nodeID, \"server\", c.Logger)\n\t\tif err != nil {\n\t\t\treturn 0, err\n\t\t}\n\n\t\tif crypto.CertificatesWithSamePublicKey(thisNodeCertAsDER, certAsDER) == nil {\n\t\t\treturn nodeID, nil\n\t\t}\n\t}\n\n\tc.Logger.Warning(\"Could not find\", string(c.Cert), \"among\", serverCertificates)\n\treturn 0, cluster.ErrNotInChannel\n}\n\n// HandleChain returns a new Chain instance or an error upon failure\nfunc (c *Consenter) HandleChain(support consensus.ConsenterSupport, metadata *common.Metadata) (consensus.Chain, error) {\n\tm := &etcdraft.ConfigMetadata{}\n\tif err := proto.Unmarshal(support.SharedConfig().ConsensusMetadata(), m); err != nil {\n\t\treturn nil, errors.Wrap(err, \"failed to unmarshal consensus metadata\")\n\t}\n\n\tif m.GetOptions() == nil {\n\t\treturn nil, errors.New(\"etcdraft options have not been provided\")\n\t}\n\n\tisMigration := (metadata == nil || len(metadata.GetValue()) == 0) && (support.Height() > 1)\n\tif isMigration {\n\t\tc.Logger.Debugf(\"Block metadata is nil at block height=%d, it is consensus-type migration\", support.Height())\n\t}\n\n\t// determine raft replica set mapping for each node to its id\n\t// for newly started chain we need to read and initialize raft\n\t// metadata by creating mapping between conseter and its id.\n\t// In case chain has been restarted we restore raft metadata\n\t// information from the recently committed block meta data\n\t// field.\n\tblockMetadata, err := ReadBlockMetadata(metadata, m)","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/consensus/etcdraft/consenter.go#L104-L140","documentation":"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.","triggerScenarios":"Orderer startup or chain creation where support.SharedConfig().ConsensusMetadata() returns bytes that fail proto.Unmarshal into etcdraft.ConfigMetadata.","commonSituations":"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.","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"],"exampleFix":"// before: embedding JSON in config\nMetadata: []byte(`{\"Consenters\":[...]}`)\n// after\nm := &etcdraft.ConfigMetadata{...}\nMetadata, _ := proto.Marshal(m) // configtxgen handles this in Channel.Consensus.Metadata","handlingStrategy":"validation","validationCode":"m := &etcdraft.ConfigMetadata{}\nif err := proto.Unmarshal(sharedConfig.ConsensusMetadata(), m); err != nil {\n    return fmt.Errorf(\"channel metadata is not a valid ConfigMetadata proto: %w\", err)\n}","typeGuard":"func isValidConfigMetadata(raw []byte) bool {\n    m := &etcdraft.ConfigMetadata{}\n    return proto.Unmarshal(raw, m) == nil && len(m.GetConsenters()) > 0\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["protobuf","raft","metadata","orderer-startup"],"backgroundTag":"consensus-metadata-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"}