{"record":{"id":"d3a246b9c821010b","repo":"hyperledger/fabric","slug":"failed-to-unmarshal-orderer-block-metadata","errorCode":null,"errorMessage":"failed to unmarshal orderer block metadata","messagePattern":"failed to unmarshal orderer block metadata","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"protoutil/blockutils.go","lineNumber":169,"sourceCode":"\n// GetConsenterMetadataFromBlock attempts to retrieve consenter metadata from the value\n// stored in block metadata at index SIGNATURES (first field). If no consenter metadata\n// is found there, it falls back to index ORDERER (third field).\nfunc GetConsenterMetadataFromBlock(block *cb.Block) (*cb.Metadata, error) {\n\tm, err := GetMetadataFromBlock(block, cb.BlockMetadataIndex_SIGNATURES)\n\tif err != nil {\n\t\treturn nil, errors.WithMessage(err, \"failed to retrieve metadata\")\n\t}\n\n\t// TODO FAB-15864 Remove this fallback when we can stop supporting upgrade from pre-1.4.1 orderer\n\tif len(m.Value) == 0 {\n\t\treturn GetMetadataFromBlock(block, cb.BlockMetadataIndex_ORDERER)\n\t}\n\n\tobm := &cb.OrdererBlockMetadata{}\n\terr = proto.Unmarshal(m.Value, obm)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"failed to unmarshal orderer block metadata\")\n\t}\n\n\tres := &cb.Metadata{}\n\terr = proto.Unmarshal(obm.ConsenterMetadata, res)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"failed to unmarshal consenter metadata\")\n\t}\n\n\treturn res, nil\n}\n\n// GetLastConfigIndexFromBlock retrieves the index of the last config block as\n// encoded in the block metadata\nfunc GetLastConfigIndexFromBlock(block *cb.Block) (uint64, error) {\n\tm, err := GetMetadataFromBlock(block, cb.BlockMetadataIndex_SIGNATURES)\n\tif err != nil {\n\t\treturn 0, errors.WithMessage(err, \"failed to retrieve metadata\")\n\t}","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/protoutil/blockutils.go#L151-L187","documentation":"GetConsenterMetadataFromBlock reads the ORDERER metadata, and when its Value is present unmarshals it into cb.OrdererBlockMetadata. This error means those Value bytes are not a valid OrdererBlockMetadata, so the consenter metadata nested inside cannot be reached. It wraps the underlying proto error.","triggerScenarios":"GetConsenterMetadataFromBlock is called (from newChainSupport, commitBlock, tests) on a block whose ORDERER metadata md.Value fails proto.Unmarshal into cb.OrdererBlockMetadata.","commonSituations":"Blocks created by non-BFT consensus (etcdraft writes different ORDERER metadata content) consumed by SmartBFT paths; corrupted ledger data; test fixtures with placeholder Value bytes.","solutions":["Ensure the block was produced by a consensus type that stores OrdererBlockMetadata in the ORDERER metadata (SmartBFT), of a compatible version","Fix test helpers (TestGoodWriteConfig etc.) to marshal a real cb.OrdererBlockMetadata into Metadata.Value","Restore the block from a healthy orderer if the ledger is corrupted","Inspect the wrapped proto error; if Value is intentionally absent, callers fall back to GetMetadataFromBlock(ORDERER) directly"],"exampleFix":"// before: test fixture writes opaque bytes\nmetadata.Value = []byte(\"junk\")\n// after\nobm := &cb.OrdererBlockMetadata{ConsenterMetadata: consenterMD, LastConfig: &cb.LastConfig{Index: 0}}\nmetadata.Value = protoMarshal(obm)","handlingStrategy":"validation","validationCode":"m, err := protoutil.GetMetadataFromBlock(blk, cb.BlockMetadataIndex_ORDERER)\nif err != nil { return err }\nif len(m.Value) > 0 {\n    obm := &cb.OrdererBlockMetadata{}\n    if err := proto.Unmarshal(m.Value, obm); err != nil {\n        return fmt.Errorf(\"ORDERER metadata Value is not OrdererBlockMetadata: %w\", err)\n    }\n}","typeGuard":"func hasParsableOrdererBlockMetadata(m *cb.Metadata) bool {\n    if m == nil || len(m.Value) == 0 { return false }\n    obm := &cb.OrdererBlockMetadata{}\n    return proto.Unmarshal(m.Value, obm) == nil\n}","tryCatchPattern":"cm, err := protoutil.GetConsenterMetadataFromBlock(blk)\nif err != nil {\n    if strings.Contains(err.Error(), \"failed to unmarshal orderer block metadata\") {\n        log.Warnf(\"block %d has corrupt ORDERER metadata; using raw ORDERER metadata fallback\", blk.Header.Number)\n        return protoutil.GetMetadataFromBlock(blk, cb.BlockMetadataIndex_ORDERER)\n    }\n    return err\n}","preventionTips":["Only consume consenter metadata on SmartBFT channels; check consensus type first","In tests (TestGoodWriteConfig etc.), marshal real cb.OrdererBlockMetadata into Metadata.Value","Validate blocks with protoutil helpers before commit paths like commitBlock","Restore corrupted blocks from a healthy orderer rather than parsing garbage bytes"],"tags":["block","orderer-metadata","protobuf","smartbft"],"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"}