hyperledger/fabric · error

at least one TransactionAction required

Error message

at least one TransactionAction required

What it means

GetActionFromEnvelopeMsg rejects transactions with no actions: after unmarshaling the Payload data into a peer.Transaction, it requires len(tx.Actions) >= 1 to extract a ChaincodeAction. An empty Actions slice means the transaction carried no endorsed proposal results, so nothing can be extracted.

Source

Thrown at protoutil/proputils.go:248

	if err != nil {
		return nil, err
	}
	return GetActionFromEnvelopeMsg(env)
}

func GetActionFromEnvelopeMsg(env *common.Envelope) (*peer.ChaincodeAction, error) {
	payl, err := UnmarshalPayload(env.Payload)
	if err != nil {
		return nil, err
	}

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

	if len(tx.Actions) == 0 {
		return nil, errors.New("at least one TransactionAction required")
	}

	_, respPayload, err := GetPayloads(tx.Actions[0])
	return respPayload, err
}

// CreateProposalFromCISAndTxid returns a proposal given a serialized identity
// and a ChaincodeInvocationSpec
func CreateProposalFromCISAndTxid(txid string, typ common.HeaderType, channelID string, cis *peer.ChaincodeInvocationSpec, creator []byte) (*peer.Proposal, string, error) {
	nonce, err := getRandomNonce()
	if err != nil {
		return nil, "", err
	}
	return CreateChaincodeProposalWithTxIDNonceAndTransient(txid, typ, channelID, cis, nonce, creator, nil)
}

// CreateProposalFromCIS returns a proposal given a serialized identity and a
// ChaincodeInvocationSpec

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Build the Transaction with protoutil.CreateTransaction / CreateSignedTx so at least one TransactionAction is appended from the ProposalResponses
  2. Validate tx.Actions length in your own code before creating/submitting the envelope
  3. If reading from a block, treat this as a malformed transaction and skip/flag it rather than retrying

Example fix

// before
action, err := protoutil.GetActionFromEnvelope(envBytes)
// after
env, _ := protoutil.UnmarshalEnvelope(envBytes)
payl, _ := protoutil.UnmarshalPayload(env.Payload)
tx, _ := protoutil.UnmarshalTransaction(payl.Data)
if tx == nil || len(tx.Actions) == 0 {
	return nil, errors.New("transaction has no actions; not processable")
}
action, err := protoutil.GetActionFromEnvelope(envBytes)
Defensive patterns

Strategy: validation

Validate before calling

env, err := protoutil.UnmarshalEnvelope(envBytes)
if err != nil { return err }
payl, err := protoutil.UnmarshalPayload(env.Payload)
if err != nil { return err }
tx, err := protoutil.UnmarshalTransaction(payl.Data)
if err != nil { return err }
if len(tx.Actions) == 0 {
	return errors.New("transaction has no actions")
}

Type guard

func txHasActions(tx *peer.Transaction) bool {
	return tx != nil && len(tx.Actions) > 0
}

Try / catch

action, err := protoutil.GetActionFromEnvelope(envBytes)
if err != nil {
	if strings.Contains(err.Error(), "at least one TransactionAction") {
		return nil, ErrMalformedTransaction
	}
	return nil, err
}

Prevention

When it happens

Trigger: Calling GetActionFromEnvelope or GetActionFromEnvelopeMsg on an envelope whose payload data deserialized to a Transaction with zero TransactionActions — e.g. a manually built Transaction, a truncated/corrupted payload, or an empty tx.Data. Also reached via retrieveRwsetForTx and submitCheckEndorsingOrgsTransaction.

Common situations: Ledger/validation code processing malformed transactions, tests constructing Transactions without appending actions, or cross-version payload corruption after protobuf migration.

Related errors


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