hyperledger/fabric · error
empty ChaincodeActionPayload
Error message
empty ChaincodeActionPayload
What it means
The TransactionAction's Payload bytes are empty, so there is no ChaincodeActionPayload to unmarshal. A valid endorser transaction action must carry a serialized ChaincodeActionPayload containing the proposal hash, endorsements, and response. An empty payload means the action was never populated.
Source
Thrown at core/tx/endorser/parser.go:74
}
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 {
return nil, errors.New("empty ChaincodeActionPayload")
}
ccActionPayload, err := protoutil.UnmarshalChaincodeActionPayload(txAction.Payload)
if err != nil {
return nil, err
}
if ccActionPayload.Action == nil {
return nil, errors.New("nil ChaincodeEndorsedAction")
}
if len(ccActionPayload.Action.ProposalResponsePayload) == 0 {
return nil, errors.New("empty ProposalResponsePayload")
}
proposalResponsePayload, err := protoutil.UnmarshalProposalResponsePayload(
ccActionPayload.Action.ProposalResponsePayload,
)View on GitHub (pinned to 2736b63f8f)
Solutions
- Populate TransactionAction.Payload with protoutil.MarshalOrPanic(&peer.ChaincodeActionPayload{...}) before building the envelope.
- Regenerate the transaction through the standard SDK submit flow (proposal -> endorse -> assemble).
- Check for byte truncation in the path that serialized/transmitted the envelope.
Example fix
// before
action := &common.TransactionAction{} // Payload empty
// after
action := &common.TransactionAction{
Payload: protoutil.MarshalOrPanic(chaincodeActionPayload),
} Defensive patterns
Strategy: validation
Validate before calling
func hasActionPayload(tx *common.Transaction) bool {
a := tx.GetActions()[0]
return a != nil && len(a.Payload) > 0
} Type guard
func hasPayload(a *common.TransactionAction) bool {
return a != nil && len(a.Payload) > 0
} Try / catch
tx, err := parser.UnmarshalEndorserTxAndValidate(env)
if err != nil {
if strings.Contains(err.Error(), "empty ChaincodeActionPayload") {
// action payload missing: regenerate transaction via SDK flow
return ErrBadTransaction
}
return err
} Prevention
- Always marshal ChaincodeActionPayload into TransactionAction.Payload.
- Verify envelope byte integrity after any storage or transport step.
- Avoid using mock/test envelopes outside of tests.
When it happens
Trigger: UnmarshalEndorserTxAndValidate receives a transaction where tx.Actions[0].Payload is a zero-length byte slice — the TransactionAction struct was created but its Payload field was never assigned.
Common situations: Custom transaction builders skipping the ChaincodeActionPayload step; truncation of protobuf bytes during transport/storage; mock/test envelopes used in production paths.
Related errors
- invalid chaincode ID
- invalid header type %s
- nil payload data
- only one transaction action is supported, %d were present
- nil action
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/8871c1b0dcaded24.
Report an issue: GitHub.