hyperledger/fabric · error

error bad proposal response %d: %s

Error message

error bad proposal response %d: %s

What it means

The endorser did return a proposal response, but its embedded response status is neither 0 (unset) nor 200 OK. The error surfaces the peer's status code and message so the caller can see why the endorsement (GetChannelConfig) was rejected.

Source

Thrown at internal/peer/common/common.go:266

		return nil, errors.WithMessage(err, "error creating GetChannelConfig proposal")
	}

	signedProp, err := protoutil.GetSignedProposal(prop, signer)
	if err != nil {
		return nil, errors.WithMessage(err, "error creating signed GetChannelConfig proposal")
	}

	proposalResp, err := endorserClient.ProcessProposal(context.Background(), signedProp)
	if err != nil {
		return nil, errors.WithMessage(err, "error endorsing GetChannelConfig")
	}

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

	if proposalResp.Response.Status != 0 && proposalResp.Response.Status != http.StatusOK {
		return nil, errors.Errorf("error bad proposal response %d: %s", proposalResp.Response.Status, proposalResp.Response.Message)
	}

	// parse config
	channelConfig := &pcommon.Config{}
	if err := proto.Unmarshal(proposalResp.Response.Payload, channelConfig); err != nil {
		return nil, errors.WithMessage(err, "error unmarshalling channel config")
	}

	bundle, err := channelconfig.NewBundle(chainID, channelConfig, cryptoProvider)
	if err != nil {
		return nil, errors.WithMessage(err, "error loading channel config")
	}

	ordererConfig, ok := bundle.OrdererConfig()
	if !ok {
		return nil, errors.New("missing OrdererConfig in channel config")
	}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Read the %s message and %d status embedded in the error to identify the peer-side cause
  2. Verify the peer has joined the target channel (peer channel list)
  3. Check the client MSP identity has read access to channel config resources
  4. Retry with a different peer joined to the channel

Example fix

// before
resp, _ := common.GetOrdererEndpointOfChain("mychannel", nil, signer, certPool)
// after
resp, err := common.GetOrdererEndpointOfChain("mychannel", nil, signer, certPool)
if err != nil { log.Fatalf("endorsement rejected: %v", err) }
Defensive patterns

Strategy: try-catch

Validate before calling

// verify peer has joined the channel before querying config
// peer channel list | grep <channelID>
// ensure the signer's MSP is enrolled and known to the peer

Type guard

if resp != nil && resp.Response != nil && (resp.Response.Status == 0 || resp.Response.Status == 200) {
    // response is usable
}

Try / catch

orderers, err := GetOrdererEndpointOfChain(chainID, dc, signer, cp)
if err != nil {
    var statusErr interface{ Status() int32 }
    log.Printf("endorsement rejected: %v", err) // status+message are embedded in the text
    return err
}

Prevention

When it happens

Trigger: endorserClient.ProcessProposal succeeds but proposalResp.Response.Status is a non-200 code, e.g. 500 (chained execution failure), 403/404 (access or unknown channel), 400 (bad proposal).

Common situations: Querying a channel the peer is not joined to (unknown channel), permission/ACL rejection for the requesting identity, chaincode/endorser internal error while loading channel config.

Related errors


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