{"record":{"id":"946add7411f2c879","repo":"hyperledger/fabric","slug":"at-least-one-transactionaction-required","errorCode":null,"errorMessage":"at least one TransactionAction required","messagePattern":"at least one TransactionAction required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"protoutil/proputils.go","lineNumber":248,"sourceCode":"\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn GetActionFromEnvelopeMsg(env)\n}\n\nfunc GetActionFromEnvelopeMsg(env *common.Envelope) (*peer.ChaincodeAction, error) {\n\tpayl, err := UnmarshalPayload(env.Payload)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\ttx, err := UnmarshalTransaction(payl.Data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(tx.Actions) == 0 {\n\t\treturn nil, errors.New(\"at least one TransactionAction required\")\n\t}\n\n\t_, respPayload, err := GetPayloads(tx.Actions[0])\n\treturn respPayload, err\n}\n\n// CreateProposalFromCISAndTxid returns a proposal given a serialized identity\n// and a ChaincodeInvocationSpec\nfunc CreateProposalFromCISAndTxid(txid string, typ common.HeaderType, channelID string, cis *peer.ChaincodeInvocationSpec, creator []byte) (*peer.Proposal, string, error) {\n\tnonce, err := getRandomNonce()\n\tif err != nil {\n\t\treturn nil, \"\", err\n\t}\n\treturn CreateChaincodeProposalWithTxIDNonceAndTransient(txid, typ, channelID, cis, nonce, creator, nil)\n}\n\n// CreateProposalFromCIS returns a proposal given a serialized identity and a\n// ChaincodeInvocationSpec","sourceCodeStart":230,"sourceCodeEnd":266,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/protoutil/proputils.go#L230-L266","documentation":"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.","triggerScenarios":"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.","commonSituations":"Ledger/validation code processing malformed transactions, tests constructing Transactions without appending actions, or cross-version payload corruption after protobuf migration.","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"],"exampleFix":"// before\naction, err := protoutil.GetActionFromEnvelope(envBytes)\n// after\nenv, _ := protoutil.UnmarshalEnvelope(envBytes)\npayl, _ := protoutil.UnmarshalPayload(env.Payload)\ntx, _ := protoutil.UnmarshalTransaction(payl.Data)\nif tx == nil || len(tx.Actions) == 0 {\n\treturn nil, errors.New(\"transaction has no actions; not processable\")\n}\naction, err := protoutil.GetActionFromEnvelope(envBytes)","handlingStrategy":"validation","validationCode":"env, err := protoutil.UnmarshalEnvelope(envBytes)\nif err != nil { return err }\npayl, err := protoutil.UnmarshalPayload(env.Payload)\nif err != nil { return err }\ntx, err := protoutil.UnmarshalTransaction(payl.Data)\nif err != nil { return err }\nif len(tx.Actions) == 0 {\n\treturn errors.New(\"transaction has no actions\")\n}","typeGuard":"func txHasActions(tx *peer.Transaction) bool {\n\treturn tx != nil && len(tx.Actions) > 0\n}","tryCatchPattern":"action, err := protoutil.GetActionFromEnvelope(envBytes)\nif err != nil {\n\tif strings.Contains(err.Error(), \"at least one TransactionAction\") {\n\t\treturn nil, ErrMalformedTransaction\n\t}\n\treturn nil, err\n}","preventionTips":["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"],"tags":["hyperledger-fabric","transaction","validation","malformed-input"],"backgroundTag":"transaction-missing-actions","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}