{"record":{"id":"32f7fd500410e798","repo":"hyperledger/fabric","slug":"bad-metadata","errorCode":null,"errorMessage":"bad metadata","messagePattern":"bad metadata","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/consensus/smartbft/signature.go","lineNumber":86,"sourceCode":"\t\tPreviousHash: hdr.PreviousHash,\n\t\tDataHash:     hdr.DataHash,\n\t}\n\n\tif len(proposal.Payload) == 0 {\n\t\treturn nil, errors.New(\"proposal payload cannot be nil\")\n\t}\n\n\ttuple := &ByteBufferTuple{}\n\tif err := tuple.FromBytes(proposal.Payload); err != nil {\n\t\treturn nil, errors.Wrap(err, \"bad payload and metadata tuple\")\n\t}\n\n\tif err := proto.Unmarshal(tuple.A, block.Data); err != nil {\n\t\treturn nil, errors.Wrap(err, \"bad payload\")\n\t}\n\n\tif err := proto.Unmarshal(tuple.B, block.Metadata); err != nil {\n\t\treturn nil, errors.Wrap(err, \"bad metadata\")\n\t}\n\treturn block, nil\n}\n\ntype asn1Header struct {\n\tNumber       *big.Int\n\tPreviousHash []byte\n\tDataHash     []byte\n}\n","sourceCodeStart":68,"sourceCodeEnd":96,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/consensus/smartbft/signature.go#L68-L96","documentation":"After successfully decoding the block Data, ProposalToBlock unmarshals tuple.B as the block's common.BlockMetadata. This error means the metadata bytes are not a valid BlockMetadata protobuf message, so the block cannot be completed.","triggerScenarios":"ProposalToBlock called where tuple.B of the Payload tuple is corrupt, truncated, or not marshalled BlockMetadata — often alongside a swapped or partially-written tuple payload.","commonSituations":"Truncated writes after power loss/unclean shutdown; custom code encoding metadata incorrectly (e.g. using a different metadata layout or signing scheme version); replayed proposals from an incompatible channel version.","solutions":["Verify tuple.B carries marshalled common.BlockMetadata in the expected order (ORDERER metadata entries).","Re-sync the node's proposal state from other consenters to replace the corrupted record.","Align Fabric versions across the consenters to avoid metadata layout mismatches.","Check for unclean shutdown/truncation in the node's ledger/WAL and restore from a healthy backup if needed."],"exampleFix":"// before\ntuple := &ByteBufferTuple{A: dataBytes, B: someRandomBytes}\n\n// after\ntuple := &ByteBufferTuple{A: dataBytes, B: protoutil.MarshalOrPanic(metadata)}","handlingStrategy":"validation","validationCode":"tuple := &ByteBufferTuple{}\nif err := tuple.FromBytes(prop.Payload); err != nil {\n    return err\n}\nmd := &common.BlockMetadata{}\nif err := proto.Unmarshal(tuple.B, md); err != nil {\n    return fmt.Errorf(\"tuple.B is not BlockMetadata: %v\", err)\n}\nblock, err := ProposalToBlock(prop)","typeGuard":"func tupleBIsBlockMetadata(p types.Proposal) bool {\n    t := &ByteBufferTuple{}\n    if t.FromBytes(p.Payload) != nil {\n        return false\n    }\n    return proto.Unmarshal(t.B, &common.BlockMetadata{}) == nil\n}","tryCatchPattern":"block, err := ProposalToBlock(prop)\nif err != nil && strings.HasSuffix(err.Error(), \"bad metadata\") {\n    // metadata corrupt: replace via resync from quorum\n    return resync()\n}","preventionTips":["Marshal metadata with the same Fabric version that writes the proposal.","Use graceful shutdown so metadata writes are never truncated.","Checksum proposal payloads on write and verify on read.","Version-gate any custom metadata layout changes."],"tags":["hyperledger-fabric","smartbft","protobuf","metadata"],"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"}