hyperledger/fabric · error
nil ChaincodeEndorsedAction
Error message
nil ChaincodeEndorsedAction
What it means
The ChaincodeActionPayload deserialized successfully but its Action field (the ChaincodeEndorsedAction holding the proposal response payload and endorsements) is nil. Without an endorsed action there are no endorsements or results to validate, so the parser rejects the transaction.
Source
Thrown at core/tx/endorser/parser.go:83
}
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,
)
if err != nil {
return nil, err
}
if len(proposalResponsePayload.Extension) == 0 {
return nil, errors.New("nil Extension")
}
ccAction, err := protoutil.UnmarshalChaincodeAction(proposalResponsePayload.Extension)View on GitHub (pinned to 2736b63f8f)
Solutions
- Set ChaincodeActionPayload.Action to a populated ChaincodeEndorsedAction (ProposalResponsePayload + Endorsements) before marshaling.
- Regenerate the transaction via the normal endorse/assemble flow so the endorsed action is always present.
- Inspect the producer of the payload for a code path that constructs it without Action.
Example fix
// before
ccPayload := &peer.ChaincodeActionPayload{Endorsements: endorsements} // Action missing
// after
ccPayload := &peer.ChaincodeActionPayload{
Action: &peer.ChaincodeEndorsedAction{
ProposalResponsePayload: prpBytes,
Endorsements: endorsements,
},
} Defensive patterns
Strategy: validation
Validate before calling
func hasEndorsedAction(ccPayloadBytes []byte) bool {
p := &peer.ChaincodeActionPayload{}
if proto.Unmarshal(ccPayloadBytes, p) != nil {
return false
}
return p.GetAction() != nil
} Type guard
func isEndorsed(p *peer.ChaincodeActionPayload) bool {
return p.GetAction() != nil && len(p.GetAction().Endorsements) > 0
} Try / catch
tx, err := parser.UnmarshalEndorserTxAndValidate(env)
if err != nil {
if strings.Contains(err.Error(), "nil ChaincodeEndorsedAction") {
// endorsed action missing: transaction has no endorsements, reject
return ErrNoEndorsement
}
return err
} Prevention
- Populate ChaincodeActionPayload.Action with proposal response payload and endorsements.
- Regenerate transactions through the standard endorse -> assemble flow.
- Audit custom builders for fields left unset.
When it happens
Trigger: UnmarshalEndorserTxAndValidate is given a transaction whose ChaincodeActionPayload.Action is nil — the payload was marshaled with only Endorsements or Extension set, or Action was omitted entirely.
Common situations: Custom transaction assembly that fills ChaincodeActionPayload but forgets the Action sub-message; protobufs built by tooling versions that left Action unset; corrupted payloads that unmarshal partially.
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/436e45d213c198cb.
Report an issue: GitHub.