{"record":{"id":"2b1927720f8a3923","repo":"hyperledger/fabric","slug":"malformed-signature-metadata","errorCode":null,"errorMessage":"malformed signature metadata","messagePattern":"malformed signature metadata","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/consensus/smartbft/verifier.go","lineNumber":428,"sourceCode":"\t\t\tbase64.StdEncoding.EncodeToString(ordererMD.ConsenterMetadata), base64.StdEncoding.EncodeToString(prop.Metadata))\n\t\treturn errors.Errorf(\"consenter metadata in OrdererBlockMetadata doesn't match proposal\")\n\t}\n\n\tblock, err := ProposalToBlock(prop)\n\tif err != nil {\n\t\tv.Logger.Warnf(\"got malformed proposal: %v\", err)\n\t\treturn err\n\t}\n\n\t// Ensure Metadata slice is of the right size\n\tif len(block.Metadata.Metadata) != len(cb.BlockMetadataIndex_name) {\n\t\treturn errors.Errorf(\"block metadata is of size %d but should be of size %d\",\n\t\t\tlen(block.Metadata.Metadata), len(cb.BlockMetadataIndex_name))\n\t}\n\n\tsignatureMetadata := &cb.Metadata{}\n\tif err := proto.Unmarshal(block.Metadata.Metadata[cb.BlockMetadataIndex_SIGNATURES], signatureMetadata); err != nil {\n\t\treturn errors.Wrap(err, \"malformed signature metadata\")\n\t}\n\n\tordererMDFromBlock := &cb.OrdererBlockMetadata{}\n\tif err := proto.Unmarshal(signatureMetadata.Value, ordererMDFromBlock); err != nil {\n\t\treturn errors.Wrap(err, \"malformed orderer metadata in block\")\n\t}\n\n\t// Ensure the block's OrdererBlockMetadata matches the signature.\n\tif !proto.Equal(ordererMDFromBlock, ordererMD) {\n\t\treturn errors.Errorf(\"signature's OrdererBlockMetadata and OrdererBlockMetadata extracted from block do not match\")\n\t}\n\n\treturn nil\n}\n\ntype consenterVerifier struct {\n\tlogger        *flogging.FabricLogger\n\tchannel       string","sourceCodeStart":410,"sourceCodeEnd":446,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/consensus/smartbft/verifier.go#L410-L446","documentation":"This error is returned by verifySignatureIsBoundToProposal in the SmartBFT verifier when the SIGNATURES entry of a block's metadata cannot be unmarshalled into a cb.Metadata protobuf. It means the raw bytes at cb.BlockMetadataIndex_SIGNATURES are corrupt or were not produced by a Hyperledger Fabric orderer. The error wraps the underlying proto.Unmarshal error.","triggerScenarios":"VerifyConsenterSig is called on a block whose Metadata.Metadata[cb.BlockMetadataIndex_SIGNATURES] contains bytes that are not a valid serialized cb.Metadata message (truncated, corrupted, or random bytes).","commonSituations":"Blocks written by non-Fabric or modified tooling; corrupted ledger files after disk issues; manual block surgery during testing; version skew where the metadata layout changed; replaying hand-crafted blocks into the verifier.","solutions":["Regenerate the block from a trusted source (configtxgen / orderer genesis) rather than repairing bytes","Verify ledger storage integrity; restore from backup or re-fetch blocks from other orderers","Check that all orderers run compatible Fabric versions producing the same metadata layout","Log and inspect the wrapped proto error to confirm the exact unmarshal failure"],"exampleFix":"// before: trusting bytes read from an external file\nmd := readBlockFromFile(\"block.bin\")\nerr := verifier.VerifyConsenterSig(md, sig)\n// after: validate metadata before verification\nsigMD := &cb.Metadata{}\nif err := proto.Unmarshal(md.Metadata[cb.BlockMetadataIndex_SIGNATURES], sigMD); err != nil {\n    return fmt.Errorf(\"skipping corrupt block: %w\", err)\n}\nerr = verifier.VerifyConsenterSig(md, sig)","handlingStrategy":"validation","validationCode":"if blk == nil || blk.Metadata == nil || len(blk.Metadata.Metadata) <= int(cb.BlockMetadataIndex_SIGNATURES) {\n    return errors.New(\"block lacks SIGNATURES metadata\")\n}\nprobe := &cb.Metadata{}\nif err := proto.Unmarshal(blk.Metadata.Metadata[cb.BlockMetadataIndex_SIGNATURES], probe); err != nil {\n    return fmt.Errorf(\"invalid signature metadata: %w\", err)\n}","typeGuard":"func hasSignatureMetadata(b *cb.Block) bool {\n    return b != nil && b.Metadata != nil && len(b.Metadata.Metadata) > int(cb.BlockMetadataIndex_SIGNATURES)\n}","tryCatchPattern":"defer func() {\n    if r := recover(); r != nil { log.Printf(\"block verification panicked: %v\", r) }\n}()\nif err := verifier.VerifyConsenterSig(blk, sig); err != nil {\n    if strings.Contains(err.Error(), \"malformed signature metadata\") {\n        log.Warnf(\"corrupt block %d: %v\", blk.Header.Number, err)\n        return errSkipBlock\n    }\n    return err\n}","preventionTips":["Only feed blocks from trusted orderer/ledger write paths into the verifier","Validate block structure (metadata presence and unmarshallability) before verification","Keep all orderer nodes on the same compatible Fabric version","Monitor ledger storage health; restore from backup on corruption"],"tags":["smartbft","consensus","protobuf","block-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"}