hyperledger/fabric · error

error unmarshalling Transaction

Error message

error unmarshalling Transaction

What it means

UnmarshalTransaction wraps any protobuf unmarshal failure of raw bytes into a peer.Transaction with this message. The library returns it whenever proto.Unmarshal rejects the input as malformed, truncated, or not a Transaction at all. It signals the caller passed bytes that cannot be interpreted as a peer.Transaction protobuf message.

Source

Thrown at protoutil/unmarshalers.go:158

// UnmarshalProposalResponsePayload unmarshals bytes to a ProposalResponsePayload
func UnmarshalProposalResponsePayload(prpBytes []byte) (*peer.ProposalResponsePayload, error) {
	prp := &peer.ProposalResponsePayload{}
	err := proto.Unmarshal(prpBytes, prp)
	return prp, errors.Wrap(err, "error unmarshalling ProposalResponsePayload")
}

// UnmarshalProposal unmarshals bytes to a Proposal
func UnmarshalProposal(propBytes []byte) (*peer.Proposal, error) {
	prop := &peer.Proposal{}
	err := proto.Unmarshal(propBytes, prop)
	return prop, errors.Wrap(err, "error unmarshalling Proposal")
}

// UnmarshalTransaction unmarshals bytes to a Transaction
func UnmarshalTransaction(txBytes []byte) (*peer.Transaction, error) {
	tx := &peer.Transaction{}
	err := proto.Unmarshal(txBytes, tx)
	return tx, errors.Wrap(err, "error unmarshalling Transaction")
}

// UnmarshalChaincodeActionPayload unmarshals bytes to a ChaincodeActionPayload
func UnmarshalChaincodeActionPayload(capBytes []byte) (*peer.ChaincodeActionPayload, error) {
	cap := &peer.ChaincodeActionPayload{}
	err := proto.Unmarshal(capBytes, cap)
	return cap, errors.Wrap(err, "error unmarshalling ChaincodeActionPayload")
}

// UnmarshalChaincodeProposalPayload unmarshals bytes to a ChaincodeProposalPayload
func UnmarshalChaincodeProposalPayload(bytes []byte) (*peer.ChaincodeProposalPayload, error) {
	cpp := &peer.ChaincodeProposalPayload{}
	err := proto.Unmarshal(bytes, cpp)
	return cpp, errors.Wrap(err, "error unmarshalling ChaincodeProposalPayload")
}

// UnmarshalTxReadWriteSet unmarshals bytes to a TxReadWriteSet
func UnmarshalTxReadWriteSet(bytes []byte) (*rwset.TxReadWriteSet, error) {

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Verify the bytes come from envelope.Payload for a TRANSACTION message (check ChannelHeader.Type == HeaderType_ENDORSER_TRANSACTION) before calling
  2. Log and hex-dump the first bytes of the input to confirm it is non-empty and plausible protobuf data
  3. Ensure the peer/protobuf definitions (fabric-protos) match the version that produced the bytes
  4. Check upstream code for double-unmarshalling: the bytes may already have been consumed or re-wrapped

Example fix

// before
tx, err := protoutil.UnmarshalTransaction(rawBytes) // may be an Envelope
// after
env, _ := protoutil.UnmarshalEnvelope(rawBytes)
if hdr, _ := protoutil.UnmarshalChannelHeader(env.Payload.Header.ChannelHeader); hdr.Type != int32(common.HeaderType_ENDORSER_TRANSACTION) { return errors.New("not a transaction") }
tx, err := protoutil.UnmarshalTransaction(env.Payload)
Defensive patterns

Strategy: validation

Validate before calling

func isEndorserTxBytes(b []byte) bool {
    if len(b) == 0 { return false }
    env, err := protoutil.UnmarshalEnvelope(b)
    if err != nil { return false }
    hdr, err := protoutil.ChannelHeader(env.Payload.Header)
    if err != nil { return false }
    return common.HeaderType(hdr.Type) == common.HeaderType_ENDORSER_TRANSACTION
}

Type guard

func safeUnmarshalTransaction(b []byte) (tx *peer.Transaction, ok bool) {
    defer func() { if recover() != nil { ok = false } }()
    tx, err := protoutil.UnmarshalTransaction(b)
    return tx, err == nil && tx != nil
}

Try / catch

tx, err := protoutil.UnmarshalTransaction(txBytes)
if err != nil {
    var protoErr *proto.UnmarshalError // or inspect wrapped error
    log.Debugf("invalid transaction bytes (%d bytes): %v", len(txBytes), err)
    return fmt.Errorf("transaction rejected: %w", err)
}

Prevention

When it happens

Trigger: Calling UnmarshalTransaction with nil or empty bytes, bytes of a different message type (e.g. an Envelope or Payload), corrupted/truncated transaction bytes, or bytes deserialized with the wrong proto definition version.

Common situations: Reading a txid from a corrupted block store, passing an envelope's payload instead of a transaction, cross-version Fabric message incompatibility, or feeding hand-crafted bytes in tests.

Related errors


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