{"record":{"id":"be6f2265ed26fc05","repo":"hyperledger/fabric","slug":"chaincode-interest-must-contain-at-least-one-chain","errorCode":null,"errorMessage":"chaincode interest must contain at least one chaincode","messagePattern":"chaincode interest must contain at least one chaincode","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"discovery/service.go","lineNumber":271,"sourceCode":"\t}\n\tif !bytes.Equal(computedHash, req.Authentication.ClientTlsCertHash) {\n\t\tclaimed := hex.EncodeToString(req.Authentication.ClientTlsCertHash)\n\t\tlogger.Warningf(\"client claimed TLS hash %s doesn't match computed TLS hash from gRPC stream %s\", claimed, hex.EncodeToString(computedHash))\n\t\treturn nil, errors.New(\"client claimed TLS hash doesn't match computed TLS hash from gRPC stream\")\n\t}\n\treturn req, nil\n}\n\nfunc validateCCQuery(ccQuery *discovery.ChaincodeQuery) error {\n\tif len(ccQuery.Interests) == 0 {\n\t\treturn errors.New(\"chaincode query must have at least one chaincode interest\")\n\t}\n\tfor _, interest := range ccQuery.Interests {\n\t\tif interest == nil {\n\t\t\treturn errors.New(\"chaincode interest is nil\")\n\t\t}\n\t\tif len(interest.Chaincodes) == 0 {\n\t\t\treturn errors.New(\"chaincode interest must contain at least one chaincode\")\n\t\t}\n\t\tfor _, cc := range interest.Chaincodes {\n\t\t\tif cc.Name == \"\" {\n\t\t\t\treturn errors.New(\"chaincode name in interest cannot be empty\")\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc wrapError(err error) *discovery.QueryResult {\n\treturn &discovery.QueryResult{\n\t\tResult: &discovery.QueryResult_Error{\n\t\t\tError: &discovery.Error{\n\t\t\t\tContent: err.Error(),\n\t\t\t},\n\t\t},\n\t}","sourceCodeStart":253,"sourceCodeEnd":289,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/discovery/service.go#L253-L289","documentation":"This error comes from the Hyperledger Fabric discovery service's chaincode query validation. A chaincode interest (discovery.ChaincodeInterest) groups chaincode call collections the client wants to endorse; each interest must name at least one chaincode. The service rejects the request before doing any discovery work because an empty interest cannot be resolved to endorsers.","triggerScenarios":"Calling the discovery service with a chaincode query whose Interests slice contains an entry created with no Chaincodes appended, e.g. discovery.ChaincodeInterest{} passed through discovery.NewQuery.Chaincode(...) or a raw ChaincodeQueryRequest built by hand.","commonSituations":"Building ChaincodeInterest programmatically and forgetting to append a ChaincodeCall; conditionally populating chaincode names from user input/config that ended up empty; serializing an interest struct before filling it.","solutions":["Populate at least one entry in interest.Chaincodes with a valid chaincode Name before sending the query","If the interest is optional for your flow, omit it from Interests instead of appending an empty one","Validate client-side: iterate Interests and skip or error on entries with len(Chaincodes)==0 before invoking discovery"],"exampleFix":"// before\ninterest := &discovery.ChaincodeInterest{}\nquery := discovery.ChaincodeQuery{Interests: []*discovery.ChaincodeInterest{interest}}\n// after\ninterest := &discovery.ChaincodeInterest{Chaincodes: []*discovery.ChaincodeCall{{Name: \"mycc\"}}}\nquery := discovery.ChaincodeQuery{Interests: []*discovery.ChaincodeInterest{interest}}","handlingStrategy":"validation","validationCode":"for _, interest := range ccQuery.Interests {\n    if interest == nil || len(interest.Chaincodes) == 0 {\n        return errors.New(\"each chaincode interest must contain at least one chaincode\")\n    }\n}","typeGuard":"func validInterest(i *discovery.ChaincodeInterest) bool {\n    return i != nil && len(i.Chaincodes) > 0\n}","tryCatchPattern":"res, err := client.Send(ctx, req)\nif err != nil {\n    if strings.Contains(err.Error(), \"must contain at least one chaincode\") {\n        // rebuild interests with valid chaincode calls\n    }\n    return err\n}","preventionTips":["Always build ChaincodeInterest via helpers that append a named ChaincodeCall","Unit-test query builders with an assertion that every interest has >=1 chaincode","Never ship a ChaincodeCall with empty Name from config defaults"],"tags":["fabric","discovery","validation","chaincode"],"backgroundTag":"empty-collection-validation","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"}