hyperledger/fabric · error
mismatched block header
Error message
mismatched block header
What it means
In SmartBFT, each consenter signs over the proposal, and the signature records the block header it signed. VerifyConsenterSig -> verifySignatureIsBoundToProposal compares the proposal's header bytes with the header in the received signature (sig.BlockHeader). This error means the signature is not bound to the proposed block — a signature from another proposal/block is being applied to this one.
Source
Thrown at orderer/consensus/smartbft/verifier.go:388
for indexInBlock := range blockData {
res = append(res, indexToRequestInfo[indexInBlock])
}
return res, nil
}
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")
}View on GitHub (pinned to 2736b63f8f)
Solutions
- Discard/re-request the signature for the correct proposal; the bad signature bundle should be dropped, not retried as-is.
- Force a view change so a fresh proposal and matching signatures are collected.
- Check for replayed messages: ensure the node's clocks/sequence handling is correct and Fabric version is uniform across consenters.
- If it follows a restart, verify the persisted signature metadata corresponds to the same block height/view as the current proposal.
Example fix
// before: signature bound to a different block prop.Header = "AAAA..."; sig.BlockHeader = "BBBB..." -> error // after: collect a signature over the actual proposal prop.Header = "AAAA..."; sig.BlockHeader = "AAAA..."
Defensive patterns
Strategy: try-catch
Validate before calling
if !bytes.Equal(sig.BlockHeader, prop.Header) {
return errors.New("signature does not bind to this proposal; request a fresh signature")
} Try / catch
err := verifier.VerifyConsenterSig(sig, identityID)
if err != nil && strings.Contains(err.Error(), "mismatched block header") {
// drop the stale signature and re-request it from the consenter
} Prevention
- Discard rather than retry mismatched signature bundles
- Force a view change after any restart that restores old signature state
- Keep BFT message sequencing strict to avoid cross-proposal message mix-ups
When it happens
Trigger: VerifyConsenterSig -> verifySignatureIsBoundToProposal: bytes.Equal(prop.Header, sig.BlockHeader) is false. Triggered when a VerificationData/signature bundle references a different proposal — e.g. message mix-up in the BFT message layer, a replayed signature from a previous block, or the signature was persisted/loaded (Sign/VerificationData round trip in verifier_assembler) against a different proposal.
Common situations: Network reordering or bugs mixing quorum messages across proposals; an attacker or faulty node replaying old signatures; process restart where signature metadata was persisted but the proposal changed; a node assembling a commit certificate from mismatched parts.
Related errors
- expected verification sequence %d, but proposal has %d
- expected metadata in block to be [view_id:%d latest_sequence
- consenter metadata in OrdererBlockMetadata doesn't match pro
- consenter options type mismatch
- unknown orderer type: %s
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/ec11c178d25bd041.
Report an issue: GitHub.