hyperledger/fabric · error

bad metadata

Error message

bad metadata

What it means

After successfully decoding the block Data, ProposalToBlock unmarshals tuple.B as the block's common.BlockMetadata. This error means the metadata bytes are not a valid BlockMetadata protobuf message, so the block cannot be completed.

Source

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

		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.B carries marshalled common.BlockMetadata in the expected order (ORDERER metadata entries).
  2. Re-sync the node's proposal state from other consenters to replace the corrupted record.
  3. Align Fabric versions across the consenters to avoid metadata layout mismatches.
  4. Check for unclean shutdown/truncation in the node's ledger/WAL and restore from a healthy backup if needed.

Example fix

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

// after
tuple := &ByteBufferTuple{A: dataBytes, B: protoutil.MarshalOrPanic(metadata)}
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

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

Try / catch

block, err := ProposalToBlock(prop)
if err != nil && strings.HasSuffix(err.Error(), "bad metadata") {
    // metadata corrupt: replace via resync from quorum
    return resync()
}

Prevention

When it happens

Trigger: ProposalToBlock called where tuple.B of the Payload tuple is corrupt, truncated, or not marshalled BlockMetadata — often alongside a swapped or partially-written tuple payload.

Common situations: Truncated writes after power loss/unclean shutdown; custom code encoding metadata incorrectly (e.g. using a different metadata layout or signing scheme version); replayed proposals from an incompatible channel version.

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/32f7fd500410e798. Report an issue: GitHub.