hyperledger/fabric · error
only one action per transaction is supported, tx contains %d
Error message
only one action per transaction is supported, tx contains %d
What it means
Hyperledger Fabric v1.x supports exactly one action per endorser transaction. validateEndorserTransaction returns this error when the unmarshalled Transaction contains more or fewer than one TransactionAction, using errors.Errorf with the actual action count.
Source
Thrown at core/common/validation/msgvalidation.go:190
// if the type is ENDORSER_TRANSACTION we unmarshal a Transaction message
tx, err := protoutil.UnmarshalTransaction(data)
if err != nil {
return err
}
// check for nil argument
if tx == nil {
return errors.New("nil transaction")
}
// TODO: validate tx.Version
// TODO: validate ChaincodeHeaderExtension
// hlf version 1 only supports a single action per transaction
if len(tx.Actions) != 1 {
return errors.Errorf("only one action per transaction is supported, tx contains %d", len(tx.Actions))
}
putilsLogger.Debugf("validateEndorserTransaction info: there are %d actions", len(tx.Actions))
for _, act := range tx.Actions {
// check for nil argument
if act == nil {
return errors.New("nil action")
}
// if the type is ENDORSER_TRANSACTION we unmarshal a SignatureHeader
sHdr, err := protoutil.UnmarshalSignatureHeader(act.Header)
if err != nil {
return err
}
// validate the SignatureHeader - here we actually only
// care about the nonce since the creator is in the outer headerView on GitHub (pinned to 2736b63f8f)
Solutions
- Build the transaction from exactly one set of collected proposal endorsements (one TransactionAction)
- If multiple proposal responses were concatenated, submit them as separate transactions
- Verify the SDK call (e.g. createTransaction with a single proposal response) rather than an array
Example fix
// before
tx.Actions = []*common.TransactionAction{action1, action2}
// after
tx.Actions = []*common.TransactionAction{action1} // one action per tx in v1.x Defensive patterns
Strategy: validation
Validate before calling
if len(tx.Actions) != 1 { return fmt.Errorf("expected 1 action, got %d", len(tx.Actions)) } Type guard
func isSingleActionTx(tx *common.Transaction) bool {
return tx != nil && len(tx.Actions) == 1
} Prevention
- Create transactions from a single proposal response set
- Never concatenate multiple proposal responses into one transaction
- On Fabric v1.x, assume exactly one action per endorser transaction
When it happens
Trigger: ValidateTransaction receiving a common.Transaction whose Actions slice length != 1 (0 actions, or 2+ actions concatenated from multiple proposals).
Common situations: Client SDKs (or custom code) merging multiple proposal responses into a single transaction; protobuf unions with Actions == nil (empty message); upgrades from formats that allowed multiple actions.
Related errors
- error unmarshalling ChaincodeHeaderExtension
- nil ChaincodeId in header extension
- nil ChaincodeId in ChaincodeAction
- invalid chaincode ID
- inconsistent ccid info (%s/%s)
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/01eb00048e5bf036.
Report an issue: GitHub.