hyperledger/fabric · error

nil payload data

Error message

nil payload data

What it means

unmarshalEndorserTx parses an envelope into an EndorserTx. After unmarshaling the envelope, the transaction payload bytes (txenv.Data) are absent. Hyperledger Fabric requires the envelope to carry a serialized Transaction containing at least one action; an empty Data field means the envelope is malformed or not an endorser transaction. The library fails fast here instead of returning a uselessly empty transaction.

Source

Thrown at core/tx/endorser/parser.go:55

	Version      int32
	Epoch        uint64
	Nonce        []byte
}

func unmarshalEndorserTx(txenv *tx.Envelope) (*EndorserTx, error) {
	if len(txenv.ChannelHeader.Extension) == 0 {
		return nil, errors.New("empty header extension")
	}

	hdrExt, err := protoutil.UnmarshalChaincodeHeaderExtension(
		txenv.ChannelHeader.Extension,
	)
	if err != nil {
		return nil, err
	}

	if len(txenv.Data) == 0 {
		return nil, errors.New("nil payload data")
	}

	tx, err := protoutil.UnmarshalTransaction(txenv.Data)
	if err != nil {
		return nil, err
	}

	if len(tx.GetActions()) != 1 {
		return nil, errors.Errorf("only one transaction action is supported, %d were present", len(tx.GetActions()))
	}

	txAction := tx.GetActions()[0]

	if txAction == nil {
		return nil, errors.New("nil action")
	}

	if len(txAction.Payload) == 0 {

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Verify the envelope is an endorser transaction envelope (Data non-empty) before calling UnmarshalEndorserTxAndValidate.
  2. Re-create the envelope using protoutil.CreateTxEnvelope / the normal submit path instead of hand-building it.
  3. If the envelope comes from a block, confirm it is an endorser tx (type TRANSACTION), not a config tx.

Example fix

// before
env := &common.Envelope{Signature: sig} // Data never set
_, err := parser.UnmarshalEndorserTxAndValidate(env)
// after
payload := protoutil.MarshalOrPanic(&common.Payload{Data: txBytes})
env := &common.Envelope{Payload: payload, Signature: sig}
_, err := parser.UnmarshalEndorserTxAndValidate(env)
Defensive patterns

Strategy: validation

Validate before calling

func hasTxData(env *common.Envelope) bool {
    payload := &common.Payload{}
    if proto.Unmarshal(env.GetPayload(), payload) != nil {
        return false
    }
    return len(payload.GetData()) > 0
}
// call before: if !hasTxData(env) { skip UnmarshalEndorserTxAndValidate }

Type guard

func isValidEndorserEnvelope(env *common.Envelope) bool {
    return env != nil && len(env.Payload) > 0
}

Try / catch

tx, err := parser.UnmarshalEndorserTxAndValidate(env)
if err != nil {
    if strings.Contains(err.Error(), "nil payload data") {
        // handle non-endorser/malformed envelope: skip or re-route
        return nil
    }
    return err
}

Prevention

When it happens

Trigger: Calling UnmarshalEndorserTxAndValidate with an envelope whose TransactionActions/Data field is empty — e.g. an envelope created from a config transaction, a nil transaction, or a hand-built envelope where the Transaction was never assigned to Data.

Common situations: Passing a config/block-envelope rather than an endorser tx envelope; constructing protoutil envelopes manually and forgetting to set Data; corruption or truncation in storage/transport that dropped the payload.

Related errors


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