hyperledger/fabric · error

expected %d endorsement descriptors but got only %d

Error message

expected %d endorsement descriptors but got only %d

What it means

mapEndorsersOfChannel expects the discovery server's ChaincodeQueryResult to contain at least one endorsement descriptor per InvocationChain the client requested. If the server returned fewer descriptors (len(ccRs.Content) < len(invocationChain)), this error reports the expected and actual counts. It indicates a client/server mismatch: the caller asked for more chaincode endorsements than the server's result carries.

Source

Thrown at discovery/client/client.go:477

		if err != nil {
			key := key{
				queryType: protoext.ChaincodeQueryType,
				k:         ch,
			}
			resp[key] = errors.New(err.Content)
			continue
		}

		if err := resp.mapEndorsersOfChannel(ccQueryRes, ch, chaincodeQueryMapping[index]); err != nil {
			return errors.Wrapf(err, "failed assembling endorsers of channel %s", ch)
		}
	}
	return nil
}

func (resp response) mapEndorsersOfChannel(ccRs *discovery.ChaincodeQueryResult, channel string, invocationChain []InvocationChain) error {
	if len(ccRs.Content) < len(invocationChain) {
		return errors.Errorf("expected %d endorsement descriptors but got only %d", len(invocationChain), len(ccRs.Content))
	}
	for i, desc := range ccRs.Content {
		expectedCCName := invocationChain[i][0].Name
		if desc.Chaincode != expectedCCName {
			return errors.Errorf("expected chaincode %s but got endorsement descriptor for %s", expectedCCName, desc.Chaincode)
		}
		key := key{
			queryType:       protoext.ChaincodeQueryType,
			k:               channel,
			invocationChain: invocationChain[i].String(),
		}

		descriptor, err := resp.createEndorsementDescriptor(desc, channel)
		if err != nil {
			return err
		}
		resp[key] = descriptor
	}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Verify every chaincode in the InvocationChain is installed on at least one peer in the channel
  2. Check the discovery client and peer Fabric versions match (v1 vs v2 discovery behavior)
  3. Re-run the discovery query after chaincode install/commit completes
  4. Reduce or correct the chaincode interest so it reflects what is actually deployed
  5. Enable discovery server debug logs to see why descriptors were omitted

Example fix

// before: requesting a chaincode that isn't installed
chaincode := InvocationChain{{Name: "mycc"}}
// after: verify deployment first, or align interest with installed chaincodes
if !isChaincodeInstalled(peer, "mycc") {
	return fmt.Errorf("mycc is not installed on any peer of the channel")
}
chaincode := InvocationChain{{Name: "mycc"}}
Defensive patterns

Strategy: validation

Validate before calling

// Verify every chaincode in the interest is installed before discovery
for _, chain := range invocationChains {
	for _, cc := range chain {
		if !isChaincodeInstalledOnChannel(channel, cc.Name) {
			return fmt.Errorf("chaincode %s not installed on channel %s", cc.Name, channel)
		}
	}
}

Try / catch

if err != nil {
	if strings.Contains(err.Error(), "endorsement descriptors but got only") {
		// fallback: re-query or reduce chaincode interest
		return retryDiscoveryQuery(ctx)
	}
	return err
}

Prevention

When it happens

Trigger: Sending a chaincode query with an InvocationChain of N entries (e.g. chaincode-to-chaincode calls or collection-based endorsement) while the discovery server returns fewer than N descriptors in ChaincodeQueryResult.Content.

Common situations: Fabric v1 client querying a v2-discovery peer where chaincode interest semantics changed; requesting endorsement for a chaincode that isn't installed anywhere in the channel so the server drops its descriptor; stale discovery data after chaincode upgrade.

Related errors


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