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
// ChaincodeInvocationSpecView on GitHub (pinned to 2736b63f8f)
Solutions
- Build the Transaction with protoutil.CreateTransaction / CreateSignedTx so at least one TransactionAction is appended from the ProposalResponses
- Validate tx.Actions length in your own code before creating/submitting the envelope
- 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
- Use CreateTransaction/CreateSignedTx so actions are always appended
- Validate incoming blocks/transactions for empty Actions before processing
- Flag zero-action transactions as malformed rather than retrying
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
- invalid chaincode ID
- invalid signed deployment spec
- invalid header type %s
- nil payload data
- only one transaction action is supported, %d were present
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/946add7411f2c879.
Report an issue: GitHub.