{"record":{"id":"8ffb2e6af0d9ad72","repo":"hyperledger/fabric","slug":"nil-presppayload-extension-8ffb2e","errorCode":null,"errorMessage":"nil pRespPayload.Extension","messagePattern":"nil pRespPayload\\.Extension","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/handlers/validation/builtin/v20/validation_logic.go","lineNumber":159,"sourceCode":"\ttx, err := protoutil.UnmarshalTransaction(payl.Data)\n\tif err != nil {\n\t\tlogger.Errorf(\"VSCC error: GetTransaction failed, err %s\", err)\n\t\treturn nil, err\n\t}\n\n\tcap, err := protoutil.UnmarshalChaincodeActionPayload(tx.Actions[actionPosition].Payload)\n\tif err != nil {\n\t\tlogger.Errorf(\"VSCC error: GetChaincodeActionPayload failed, err %s\", err)\n\t\treturn nil, err\n\t}\n\n\tpRespPayload, err := protoutil.UnmarshalProposalResponsePayload(cap.Action.ProposalResponsePayload)\n\tif err != nil {\n\t\terr = fmt.Errorf(\"GetProposalResponsePayload error %s\", err)\n\t\treturn nil, err\n\t}\n\tif pRespPayload.Extension == nil {\n\t\terr = fmt.Errorf(\"nil pRespPayload.Extension\")\n\t\treturn nil, err\n\t}\n\trespPayload, err := protoutil.UnmarshalChaincodeAction(pRespPayload.Extension)\n\tif err != nil {\n\t\terr = fmt.Errorf(\"GetChaincodeAction error %s\", err)\n\t\treturn nil, err\n\t}\n\n\treturn &validationArtifacts{\n\t\trwset:        respPayload.Results,\n\t\tprp:          cap.Action.ProposalResponsePayload,\n\t\tendorsements: cap.Action.Endorsements,\n\t\tchdr:         chdr,\n\t\tenv:          env,\n\t\tpayl:         payl,\n\t\tcap:          cap,\n\t}, nil\n}","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/handlers/validation/builtin/v20/validation_logic.go#L141-L177","documentation":"Returned by v20 extractValidationArtifacts when the proposal response payload decodes but its Extension is nil — the chaincode action bytes are missing from the endorsed payload, so validation artifacts cannot be extracted.","triggerScenarios":"A ProposalResponsePayload was constructed without populating Extension (e.g. an endorsement built by custom code that only set ProposalHash), or Extension was explicitly nil in the serialized bytes.","commonSituations":"Custom SDK or hand-rolled endorsement code omitting the ChaincodeAction extension; truncated/zeroed transaction data from a bad write path; crafted malicious transactions.","solutions":["Ensure complete endorsements with a ChaincodeAction extension","Reject the incomplete transaction"],"exampleFix":"// before\nprp := &peer.ProposalResponsePayload{ProposalHash: hash} // Extension missing\n// after\nprp := &peer.ProposalResponsePayload{\n    ProposalHash: hash,\n    Extension:    protoutil.MarshalOrPanic(&peer.ChaincodeAction{Results: rwset}),\n}","handlingStrategy":"validation","validationCode":"prp := &peer.ProposalResponsePayload{}\nif err := proto.Unmarshal(capBytes, prp); err == nil {\n    if prp.Extension == nil {\n        return fmt.Errorf(\"endorsement missing ChaincodeAction extension\")\n    }\n}","typeGuard":"func hasExtension(prp *peer.ProposalResponsePayload) bool {\n    return prp != nil && prp.Extension != nil\n}","tryCatchPattern":"artifacts, err := extractValidationArtifacts(bytes, policy)\nif err != nil {\n    if strings.Contains(err.Error(), \"nil pRespPayload.Extension\") {\n        return nil, validationerrors.TXMalformed\n    }\n    return nil, err\n}","preventionTips":["Always populate ProposalResponsePayload.Extension when building endorsements","Prefer SDK endorsement flows over manual proto assembly","Test custom endorser code against the standard validation path","Log the txID when rejecting to trace the offending client"],"tags":["fabric","malformed-transaction","endorsement"],"backgroundTag":"malformed-endorsement-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"}