{"record":{"id":"8608b2d733f445ae","repo":"hyperledger/fabric","slug":"nil-action-8608b2","errorCode":null,"errorMessage":"nil action","messagePattern":"nil action","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/tx/endorser/parser.go","lineNumber":70,"sourceCode":"\t}\n\n\tif len(txenv.Data) == 0 {\n\t\treturn nil, errors.New(\"nil payload data\")\n\t}\n\n\ttx, err := protoutil.UnmarshalTransaction(txenv.Data)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif len(tx.GetActions()) != 1 {\n\t\treturn nil, errors.Errorf(\"only one transaction action is supported, %d were present\", len(tx.GetActions()))\n\t}\n\n\ttxAction := tx.GetActions()[0]\n\n\tif txAction == nil {\n\t\treturn nil, errors.New(\"nil action\")\n\t}\n\n\tif len(txAction.Payload) == 0 {\n\t\treturn nil, errors.New(\"empty ChaincodeActionPayload\")\n\t}\n\n\tccActionPayload, err := protoutil.UnmarshalChaincodeActionPayload(txAction.Payload)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tif ccActionPayload.Action == nil {\n\t\treturn nil, errors.New(\"nil ChaincodeEndorsedAction\")\n\t}\n\n\tif len(ccActionPayload.Action.ProposalResponsePayload) == 0 {\n\t\treturn nil, errors.New(\"empty ProposalResponsePayload\")\n\t}","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/tx/endorser/parser.go#L52-L88","documentation":"The single TransactionAction present in the transaction is nil. This happens when the protobuf Transaction serialized a null action pointer in its Actions slice. The parser checks the element after selecting it to avoid a nil-pointer dereference downstream.","triggerScenarios":"UnmarshalEndorserTxAndValidate is given an envelope whose Transaction.Actions[0] deserialized to nil — e.g. an action pointer appended to the slice without being populated before marshaling.","commonSituations":"Hand-built transactions where append(tx.Actions, nil) or an uninitialized struct pointer was marshaled; bugs in custom transaction-generation tooling.","solutions":["Rebuild the transaction ensuring each TransactionAction is a fully populated struct before marshaling.","Add a client-side check that tx.Actions[0] != nil before creating the envelope.","Trace the code that produced the transaction and fix the nil pointer assignment."],"exampleFix":"// before\nvar action *common.TransactionAction // left nil\ntx.Actions = []*common.TransactionAction{action}\n// after\naction := &common.TransactionAction{Payload: chaincodeActionPayloadBytes}\ntx.Actions = []*common.TransactionAction{action}","handlingStrategy":"type-guard","validationCode":"func hasPopulatedAction(tx *common.Transaction) bool {\n    actions := tx.GetActions()\n    return len(actions) > 0 && actions[0] != nil\n}","typeGuard":"func isNotNilAction(a *common.TransactionAction) bool {\n    return a != nil\n}","tryCatchPattern":"tx, err := parser.UnmarshalEndorserTxAndValidate(env)\nif err != nil {\n    if strings.Contains(err.Error(), \"nil action\") {\n        // transaction was built with a nil action: reject/regenerate\n        return ErrBadTransaction\n    }\n    return err\n}","preventionTips":["Never append pointers to tx.Actions without initializing them.","Run a sanity check on the Transaction struct before marshaling.","Add unit tests for the transaction builder covering fully populated actions."],"tags":["hyperledger-fabric","transaction","validation"],"backgroundTag":"malformed-envelope-payload","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"}