hyperledger/fabric · error

bad payload

Error message

bad payload

What it means

After decoding the ByteBufferTuple from the proposal Payload, tuple.A is unmarshalled as the block's protobuf BlockData. This error means those bytes are not a valid common.BlockData protobuf message.

Source

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

	}

	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 {
		return nil, errors.Wrap(err, "bad payload")
	}

	if err := proto.Unmarshal(tuple.B, block.Metadata); err != nil {
		return nil, errors.Wrap(err, "bad metadata")
	}
	return block, nil
}

type asn1Header struct {
	Number       *big.Int
	PreviousHash []byte
	DataHash     []byte
}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Verify tuple field order: A must be the marshalled block Data, B the marshalled Metadata; swap if reversed.
  2. Discard the proposal and re-synchronize the channel from a healthy quorum of consenters.
  3. Confirm all nodes run a compatible Fabric version producing identical block encoding.
  4. Check storage medium integrity (fsck/SMART) if corruption recurs on the same node.

Example fix

// before
tuple := &ByteBufferTuple{A: metaBytes, B: dataBytes} // swapped

// after
tuple := &ByteBufferTuple{A: dataBytes, B: metaBytes}
Defensive patterns

Strategy: validation

Validate before calling

tuple := &ByteBufferTuple{}
if err := tuple.FromBytes(prop.Payload); err != nil {
    return err
}
bd := &common.BlockData{}
if err := proto.Unmarshal(tuple.A, bd); err != nil {
    return fmt.Errorf("tuple.A is not BlockData: %v", err)
}
block, err := ProposalToBlock(prop)

Type guard

func tupleAIsBlockData(p types.Proposal) bool {
    t := &ByteBufferTuple{}
    if t.FromBytes(p.Payload) != nil {
        return false
    }
    return proto.Unmarshal(t.A, &common.BlockData{}) == nil
}

Try / catch

block, err := ProposalToBlock(prop)
if err != nil && strings.HasPrefix(err.Error(), "bad payload") && !strings.Contains(err.Error(), "metadata") {
    // block data corrupt: discard and resync
    return resync()
}

Prevention

When it happens

Trigger: ProposalToBlock called where tuple.A of the decoded Payload is corrupt or not a marshalled BlockData — e.g. swapped tuple fields (data/metadata reversed), foreign protobuf bytes, or bit corruption in transit/storage.

Common situations: Hand-rolled proposal construction placing the wrong bytes in tuple.A; corrupted WAL/ledger records; a proposal relayed through non-Fabric tooling that re-encoded the bytes.

Understand the failure class

Background: "cannot parse invalid wire-format data", "cannot unmarshal", "failed unmarshalling": protobuf unmarshal errors explained — this error's family across 10 libraries.

Related errors


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