hyperledger/fabric · error

bad header

Error message

bad header

What it means

While converting a SmartBFT proposal to a block, the proposal Header bytes failed ASN.1 unmarshalling into the internal asn1Header struct. The header is present but not decodable, so the error wraps the asn1 failure with the context 'bad header'.

Source

Thrown at orderer/consensus/smartbft/signature.go:63

	return msg2Sign
}

// ProposalToBlock marshals the proposal the block
func ProposalToBlock(proposal types.Proposal) (*cb.Block, error) {
	// initialize block with empty fields
	block := &cb.Block{
		Data:     &cb.BlockData{},
		Metadata: &cb.BlockMetadata{},
	}

	if len(proposal.Header) == 0 {
		return nil, errors.New("proposal header cannot be nil")
	}

	hdr := &asn1Header{}

	if _, err := asn1.Unmarshal(proposal.Header, hdr); err != nil {
		return nil, errors.Wrap(err, "bad header")
	}

	block.Header = &cb.BlockHeader{
		Number:       hdr.Number.Uint64(),
		PreviousHash: hdr.PreviousHash,
		DataHash:     hdr.DataHash,
	}

	if len(proposal.Payload) == 0 {
		return nil, errors.New("proposal payload cannot be nil")
	}

	tuple := &ByteBufferTuple{}
	if err := tuple.FromBytes(proposal.Payload); err != nil {
		return nil, errors.Wrap(err, "bad payload and metadata tuple")
	}

	if err := proto.Unmarshal(tuple.A, block.Data); err != nil {

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Verify the Fabric binaries on all consenters are the same version (peer/orderer version alignment).
  2. Delete corrupted local state and re-sync the channel from other consenters (restart the orderer to trigger synchronization).
  3. Check storage integrity (WAL/ledger files) on the node; restore from a healthy snapshot/backup if corruption is confirmed.
  4. If the data came from the network, inspect whether a peer is sending malformed messages and verify TLS/cluster communication integrity.

Example fix

// before
// consuming a proposal from an old, incompatible WAL entry
prop := readFromWALUnchecked()
block, err := ProposalToBlock(prop)

// after
// validate source and re-sync if version skew suspected
if !sameFabricVersion(clusterPeers) {
    return resyncFromQuorum()
}
block, err := ProposalToBlock(prop)
Defensive patterns

Strategy: validation

Validate before calling

hdr := &asn1Header{}
if _, err := asn1.Unmarshal(prop.Header, hdr); err != nil {
    return fmt.Errorf("proposal header not ASN.1 decodable: %v", err)
}
block, err := ProposalToBlock(prop)

Type guard

func headerDecodable(p types.Proposal) bool {
    hdr := &asn1Header{}
    _, err := asn1.Unmarshal(p.Header, hdr)
    return err == nil && hdr.Number != nil
}

Try / catch

block, err := ProposalToBlock(prop)
if err != nil && strings.HasPrefix(err.Error(), "bad header") {
    // treat proposal as corrupted: resync from quorum
    return resync()
}

Prevention

When it happens

Trigger: VerifyProposal/SignProposal/RequestsFromProposal/Deliver called with a Proposal whose Header is corrupted, truncated, or was produced by an incompatible encoding version (not the ASN.1 asn1Header layout).

Common situations: Binary corruption during backup/restore or WAL replay; version skew between Fabric binaries after an upgrade where header encoding changed; hand-crafted or replayed messages injected by a malicious or buggy peer.

Related errors


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