hyperledger/fabric · error

malformed signature header

Error message

malformed signature header

What it means

Each consenter signature carries an IdentifierHeader (protobuf) binding the signature to a consenter identity number. VerifyConsenterSig -> verifySignatureIsBoundToProposal unmarshals it and this error means the bytes are not a valid IdentifierHeader — the signature's IdentifierHeader field is empty, truncated, or corrupted.

Source

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

func (v *Verifier) verifySignatureIsBoundToProposal(sig *Signature, identityID uint64, prop types.Proposal) error {
	// We verify the following fields:
	// ConsenterMetadata    []byte
	// SignatureHeader      []byte
	// BlockHeader          []byte
	// OrdererBlockMetadata []byte

	// Ensure block header is equal
	if !bytes.Equal(prop.Header, sig.BlockHeader) {
		v.Logger.Errorf("Expected block header %s but got %s", base64.StdEncoding.EncodeToString(prop.Header),
			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")
	}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Discard the malformed signature and re-request it from the signing consenter.
  2. Confirm all ordering nodes run the same Fabric version so IdentifierHeader encoding is identical.
  3. Enable debug logging on the BFT message layer to find where the payload got truncated or corrupted.
  4. If it follows a restart from persisted state, delete/refresh the corrupted signature metadata (view/sequence data) and re-join the consensus flow.

Example fix

// before: truncated signature payload
sig.IdentifierHeader = []byte{0x0a, 0x05} // invalid proto -> error
// after: valid marshalled IdentifierHeader
sig.IdentifierHeader = protoutil.MarshalOrPanic(&cb.IdentifierHeader{Identifier: uint32(2)})
Defensive patterns

Strategy: type-guard

Validate before calling

if len(sig.IdentifierHeader) == 0 {
    return errors.New("signature has empty IdentifierHeader; reject message")
}

Type guard

func validIdentifierHeader(b []byte) bool {
    h := &cb.IdentifierHeader{}
    return len(b) > 0 && proto.Unmarshal(b, h) == nil
}

Try / catch

err := verifier.VerifyConsenterSig(sig, id)
if err != nil && strings.Contains(err.Error(), "malformed signature header") {
    // discard corrupted signature and re-request from consenter
}

Prevention

When it happens

Trigger: VerifyConsenterSig -> verifySignatureIsBoundToProposal: proto.Unmarshal(sig.IdentifierHeader, sigHdr) returns an error — sig.IdentifierHeader is nil/empty or contains garbage bytes. Happens when a VerificationData blob is malformed, truncated in transit, or produced by incompatible code.

Common situations: Corrupted BFT message over the network; version skew between nodes producing different signature payloads; a replayed or hand-assembled VerificationData file; storage corruption of persisted signature metadata.

Understand the failure class

Related errors


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