hyperledger/fabric · error

malformed orderer metadata in signature

Error message

malformed orderer metadata in signature

What it means

The consenter metadata (opaque consensus-related bytes) inside the signature's OrdererBlockMetadata must byte-match the metadata attached to the proposal. This error means the signature was computed over different consenter metadata than what the proposal carries, so the signature cannot be bound to this proposal.

Source

Thrown at orderer/consensus/smartbft/verifier.go:405

			base64.StdEncoding.EncodeToString(sig.BlockHeader))
		return errors.Errorf("mismatched block header")
	}

	// Ensure signature header matches the identity
	sigHdr := &cb.IdentifierHeader{}
	if err := proto.Unmarshal(sig.IdentifierHeader, sigHdr); err != nil {
		return errors.Wrap(err, "malformed signature header")
	}
	if identityID != uint64(sigHdr.Identifier) {
		v.Logger.Warnf("Expected identity %d but got %d", identityID,
			sigHdr.Identifier)
		return errors.Errorf("identity in signature header does not match expected identity")
	}

	// Ensure orderer block metadata's consenter MD matches the proposal
	ordererMD := &cb.OrdererBlockMetadata{}
	if err := proto.Unmarshal(sig.OrdererBlockMetadata, ordererMD); err != nil {
		return errors.Wrap(err, "malformed orderer metadata in signature")
	}

	if !bytes.Equal(ordererMD.ConsenterMetadata, prop.Metadata) {
		v.Logger.Warnf("Expected consenter metadata %s but got %s in proposal",
			base64.StdEncoding.EncodeToString(ordererMD.ConsenterMetadata), base64.StdEncoding.EncodeToString(prop.Metadata))
		return errors.Errorf("consenter metadata in OrdererBlockMetadata doesn't match proposal")
	}

	block, err := ProposalToBlock(prop)
	if err != nil {
		v.Logger.Warnf("got malformed proposal: %v", err)
		return err
	}

	// Ensure Metadata slice is of the right size
	if len(block.Metadata.Metadata) != len(cb.BlockMetadataIndex_name) {
		return errors.Errorf("block metadata is of size %d but should be of size %d",
			len(block.Metadata.Metadata), len(cb.BlockMetadataIndex_name))

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Drop the mismatched signature and re-request signature collection for the current proposal.
  2. Upgrade all consenters to the same Fabric version to ensure identical consenter metadata encoding.
  3. Force a view change so a fresh proposal with consistent consenter metadata is proposed and signed.
  4. If persistent, enable BFT debug logs and compare the base64 metadata from the log line to identify which field differs.

Example fix

// before
ordererMD.ConsenterMetadata = "old-rotation-md"; prop.Metadata = "new-rotation-md" -> error
// after: signer embeds proposal's metadata verbatim
ordererMD.ConsenterMetadata = prop.Metadata
Defensive patterns

Strategy: validation

Validate before calling

if !bytes.Equal(ordererMD.GetConsenterMetadata(), prop.Metadata) {
    return errors.New("signature consenter metadata differs from proposal; request fresh signature")
}

Try / catch

err := verifier.VerifyConsenterSig(sig, id)
if err != nil && strings.Contains(err.Error(), "doesn't match proposal") {
    // drop signature, trigger re-proposal/view change
}

Prevention

When it happens

Trigger: VerifyConsenterSig -> verifySignatureIsBoundToProposal: bytes.Equal(ordererMD.ConsenterMetadata, prop.Metadata) is false — the OrdererBlockMetadata in the signature holds different consenter metadata bytes than prop.Metadata. Triggered by replayed signatures from another proposal or by a signing node that embedded different consenter metadata (e.g. different leader/rotation info) than the proposer.

Common situations: Mixed Fabric versions encoding consenter metadata differently; a node with a stale view producing metadata from a previous leader rotation; replayed or cross-proposal signature reuse; message corruption.

Understand the failure class

Related errors


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/f4b49dfd4444db14. Report an issue: GitHub.