hyperledger/fabric · error

received proposal response with nil response

Error message

received proposal response with nil response

What it means

After confirming the ProposalResponse itself is non-nil, Get verifies the embedded Response message is also non-nil before reading Status/Payload. A nil Response means the endorser returned a structurally incomplete reply. Like the nil proposal response check, this is defensive validation of endorser output.

Source

Thrown at internal/peer/lifecycle/chaincode/getinstalledpackage.go:139

		return errors.WithMessage(err, "failed to create proposal")
	}

	signedProposal, err := signProposal(proposal, i.Signer)
	if err != nil {
		return errors.WithMessage(err, "failed to create signed proposal")
	}

	proposalResponse, err := i.EndorserClient.ProcessProposal(context.Background(), signedProposal)
	if err != nil {
		return errors.WithMessage(err, "failed to endorse proposal")
	}

	if proposalResponse == nil {
		return errors.New("received nil proposal response")
	}

	if proposalResponse.Response == nil {
		return errors.New("received proposal response with nil response")
	}

	if proposalResponse.Response.Status != int32(cb.Status_SUCCESS) {
		return errors.Errorf("proposal failed with status: %d - %s", proposalResponse.Response.Status, proposalResponse.Response.Message)
	}

	return i.writePackage(proposalResponse)
}

func (i *InstalledPackageGetter) writePackage(proposalResponse *pb.ProposalResponse) error {
	result := &lb.GetInstalledChaincodePackageResult{}
	err := proto.Unmarshal(proposalResponse.Response.Payload, result)
	if err != nil {
		return errors.Wrap(err, "failed to unmarshal proposal response's response payload")
	}

	outputFile := filepath.Join(i.Input.OutputDirectory, i.Input.PackageID+".tar.gz")

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Fix the producing endorser/client/mock to include a pb.Response with Status and Payload
  2. Add a guard before consuming the response if writing custom client code
  3. Use the stock fabric endorser client path where this cannot occur

Example fix

// before
return &pb.ProposalResponse{}, nil // Response nil
// after
return &pb.ProposalResponse{Response: &pb.Response{Status: 200, Payload: resultBytes}}, nil
Defensive patterns

Strategy: type-guard

Type guard

func hasInnerResponse(pr *pb.ProposalResponse) bool {
    return pr != nil && pr.Response != nil
}

Try / catch

if resp == nil {
    return errors.New("received nil proposal response")
}
if resp.Response == nil {
    return errors.New("received proposal response with nil response")
}
if resp.Response.Status != int32(cb.Status_SUCCESS) {
    return fmt.Errorf("proposal failed with status: %d - %s", resp.Response.Status, resp.Response.Message)
}

Prevention

When it happens

Trigger: ProcessProposal returns a ProposalResponse with a nil Response field — again only via custom clients, interceptors, or test mocks that populate the outer struct but not Response.

Common situations: Partially constructed responses in test mocks; middleware rewriting responses and dropping the inner message.

Related errors


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/d598a92697eea71c. Report an issue: GitHub.