{"record":{"id":"9b20cff5320d83fd","repo":"hyperledger/fabric","slug":"received-proposal-response-with-nil-response-9b20cf","errorCode":null,"errorMessage":"received proposal response with nil response","messagePattern":"received proposal response with nil response","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/peer/lifecycle/chaincode/commit.go","lineNumber":196,"sourceCode":"\t\t}\n\t\tresponses = append(responses, proposalResponse)\n\t}\n\n\tif len(responses) == 0 {\n\t\t// this should only be empty due to a programming bug\n\t\treturn errors.New(\"no proposal responses received\")\n\t}\n\n\t// all responses will be checked when the signed transaction is created.\n\t// for now, just set this so we check the first response's status\n\tproposalResponse := responses[0]\n\n\tif proposalResponse == nil {\n\t\treturn errors.New(\"received nil proposal response\")\n\t}\n\n\tif proposalResponse.Response == nil {\n\t\treturn errors.New(\"received proposal response with nil response\")\n\t}\n\n\tif proposalResponse.Response.Status != int32(cb.Status_SUCCESS) {\n\t\treturn errors.Errorf(\"proposal failed with status: %d - %s\", proposalResponse.Response.Status, proposalResponse.Response.Message)\n\t}\n\t// assemble a signed transaction (it's an Envelope message)\n\tenv, err := protoutil.CreateSignedTx(proposal, c.Signer, responses...)\n\tif err != nil {\n\t\treturn errors.WithMessage(err, \"failed to create signed transaction\")\n\t}\n\n\tvar dg *chaincode.DeliverGroup\n\tvar ctx context.Context\n\tif c.Input.WaitForEvent {\n\t\tvar cancelFunc context.CancelFunc\n\t\tctx, cancelFunc = context.WithTimeout(context.Background(), c.Input.WaitForEventTimeout)\n\t\tdefer cancelFunc()\n","sourceCodeStart":178,"sourceCodeEnd":214,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/internal/peer/lifecycle/chaincode/commit.go#L178-L214","documentation":"Even when the ProposalResponse wrapper is non-nil, its embedded Response payload must be present for Commit to inspect the status. A nil Response is treated as a malformed endorser reply and rejected.","triggerScenarios":"responses[0].Response is nil when Commit examines the first proposal response — a structurally malformed response from an endorser.","commonSituations":"Corrupted or hand-crafted proposal responses in custom tooling; proto deserialization producing a non-nil wrapper with nil payload; buggy mock endorsers in tests.","solutions":["Check the endorser's returned ProposalResponse for a non-nil Response field before appending.","Verify protobuf serialization/deserialization of responses in custom clients.","Use the fabric protoutil helpers to construct responses correctly.","Re-run the transaction against healthy endorsers."],"exampleFix":"// before\nresponses = append(responses, resp)\n// after\nif resp == nil || resp.Response == nil { return errors.New(\"malformed proposal response\") }\nresponses = append(responses, resp)","handlingStrategy":"type-guard","validationCode":"for _, resp := range responses {\n    if resp == nil || resp.Response == nil {\n        return errors.New(\"malformed proposal response: nil Response\")\n    }\n}","typeGuard":"func hasResponsePayload(r *pb.ProposalResponse) bool { return r != nil && r.Response != nil }","tryCatchPattern":"if err := commit(...); err != nil {\n    if strings.Contains(err.Error(), \"nil response\") {\n        // re-endorse; inspect protobuf deserialization in custom clients\n    }\n}","preventionTips":["Validate the full ProposalResponse structure, not just the pointer.","Use fabric protoutil/protobuf helpers for serializing responses.","Re-endorse from healthy peers when responses are malformed."],"tags":["hyperledger-fabric","nil-check","proposal-response","malformed-response"],"backgroundTag":"nil-proposal-response","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"}