hyperledger/fabric · error

proposal failed with status: %d - %s

Error message

proposal failed with status: %d - %s

What it means

This error is thrown in ApproverForMyOrg.Approve when the peer's endorsement of the _lifecycle ApproveChaincodeDefinitionForMyOrg proposal returned a non-SUCCESS status. It means the peer rejected the chaincode definition approval; the gRPC Status and Message from the proposal response are embedded to explain why. Common causes are lifecycle precheck failures, a mismatched sequence number, or the chaincode package not being installed on that peer.

Source

Thrown at internal/peer/lifecycle/chaincode/approveformyorg.go:202

	if len(responses) == 0 {
		// this should only be empty due to a programming bug
		return errors.New("no proposal responses received")
	}

	// all responses will be checked when the signed transaction is created.
	// for now, just set this so we check the first response's status
	proposalResponse := responses[0]

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

	if proposalResponse.Response == nil {
		return errors.Errorf("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)
	}
	// assemble a signed transaction (it's an Envelope message)
	env, err := protoutil.CreateSignedTx(proposal, a.Signer, responses...)
	if err != nil {
		return errors.WithMessage(err, "failed to create signed transaction")
	}
	var dg *chaincode.DeliverGroup
	var ctx context.Context
	if a.Input.WaitForEvent {
		var cancelFunc context.CancelFunc
		ctx, cancelFunc = context.WithTimeout(context.Background(), a.Input.WaitForEventTimeout)
		defer cancelFunc()

		dg = chaincode.NewDeliverGroup(
			a.DeliverClients,
			a.Input.PeerAddresses,
			a.Signer,
			a.Certificate,

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Check the Message in the error output — it carries the peer's rejection reason (e.g. 'chaincode with name X and version Y already approved with sequence Z').
  2. Verify the chaincode package is installed on the peer: `peer lifecycle chaincode queryinstalled` and confirm the packageID matches --package-id.
  3. Run `peer lifecycle chaincode queryapproved` / check `checkcommitreadiness` to confirm the correct sequence number; increment sequence if the definition already exists.
  4. If the definition was already approved with identical fields, no action needed — proceed to checkcommitreadiness/commit instead of re-approving.
  5. Fix any initRequired or collection config mismatches versus the committed definition and rerun with -C/--channelID and correct flags.

Example fix

// before: approving with stale sequence and wrong package id
approveformyorg --channelID mychannel --name mycc --version 1.0 --sequence 1 --package-id cc_1:abc
// after: query installed, use current package id, bump sequence to next expected
peer lifecycle chaincode queryinstalled
approveformyorg --channelID mychannel --name mycc --version 1.0 --sequence 2 --package-id mycc_1:<correct-hash>
Defensive patterns

Strategy: validation

Validate before calling

// before approving, verify package is installed and sequence is next
out, _ := exec.Command("peer", "lifecycle", "chaincode", "queryinstalled").Output()
if !strings.Contains(string(out), expectedPackageID) {
    return errors.New("package not installed on peer; approve will fail")
}
// also compare sequence against queryapproved / committed state
readiness, _ := exec.Command("peer", "lifecycle", "chaincode", "checkcommitreadiness",
    "--channelID", ch, "--name", cc, "--version", v, "--sequence", seq, "--output", "json").Output()
_ = readiness

Try / catch

resp, err := approver.Approve(proposal)
if err != nil {
    var statusErr interface{ Status() int32 }
    // inspect proposalResponse.Response.Status/Message to branch on
    // 410/ALREADY_APPROVED-style messages vs hard failures
    return fmt.Errorf("approve rejected: %w", err)
}

Prevention

When it happens

Trigger: Running `peer lifecycle chaincode approveformyorg` where the proposal response from the peer has Response.Status != 200. Specific causes include: packageID not installed on the peer, sequence number lower than the current defined sequence, initRequired mismatch with the previous definition, collection/configuration changes failing validation, or the peer not having the org's endorsement of prerequisites.

Common situations: Approving a definition whose sequence was already approved (stale sequence), approving before `peer lifecycle chaincode install` on the peer so the packageID is unknown, a typo'd packageID after re-packaging, or endorsement policy/collection changes rejected by the peer's definition validation.

Related errors


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