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
- Verify tuple.B carries marshalled common.BlockMetadata in the expected order (ORDERER metadata entries).
- Re-sync the node's proposal state from other consenters to replace the corrupted record.
- Align Fabric versions across the consenters to avoid metadata layout mismatches.
- 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
- Marshal metadata with the same Fabric version that writes the proposal.
- Use graceful shutdown so metadata writes are never truncated.
- Checksum proposal payloads on write and verify on read.
- Version-gate any custom metadata layout changes.
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
- failed to unmarshal BFT metadata configuration
- failed to marshal request envelope: proto: Marshal called wi
- invalid consensus type property in config: %v
- invalid options encoded in consensus metadata: %v
- bad payload
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/32f7fd500410e798.
Report an issue: GitHub.