{"record":{"id":"302de2bc31ca1490","repo":"hyperledger/fabric","slug":"chaincode-query-must-have-at-least-one-chaincode-i","errorCode":null,"errorMessage":"chaincode query must have at least one chaincode interest","messagePattern":"chaincode query must have at least one chaincode interest","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"discovery/service.go","lineNumber":264,"sourceCode":"\t}\n\tif !tlsEnabled {\n\t\treturn req, nil\n\t}\n\tcomputedHash := certHashFromContext(ctx)\n\tif len(computedHash) == 0 {\n\t\treturn nil, errors.New(\"client didn't send a TLS certificate\")\n\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 {","sourceCodeStart":246,"sourceCodeEnd":282,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/discovery/service.go#L246-L282","documentation":"validateCCQuery rejects a ChaincodeQuery whose Interests slice is empty. A chaincode discovery query exists to resolve endorsements for specific chaincodes/collections, so a query with no interests is meaningless and structurally invalid.","triggerScenarios":"Calling the chaincode discovery query (via chaincodeQuery, invoked from Discover) with a discovery.ChaincodeQuery that has zero entries in Interests.","commonSituations":"Building the query programmatically with an empty slice because chaincode names were read from an empty config; a filter loop that dropped all interests; SDK call where the chaincodes argument was omitted or an empty array was passed.","solutions":["Add at least one ChaincodeInterest naming the chaincode(s) to discover before sending the query","Fix the upstream config/lookup that produced an empty chaincode list","Validate client-side that len(interests) > 0 before invoking the discovery call"],"exampleFix":"// before\nquery := &discovery.ChaincodeQuery{Interests: []discovery.ChaincodeInterest{}}\n// after\nquery := &discovery.ChaincodeQuery{Interests: []discovery.ChaincodeInterest{{Chaincodes: []discovery.ChaincodeCall{{Name: \"mycc\"}}}}}","handlingStrategy":"validation","validationCode":"func validateChaincodeQuery(q *discovery.ChaincodeQuery) error {\n    if q == nil || len(q.Interests) == 0 {\n        return errors.New(\"chaincode query requires at least one interest\")\n    }\n    return nil\n}","typeGuard":"func hasInterests(q *discovery.ChaincodeQuery) bool {\n    return q != nil && len(q.Interests) > 0\n}","tryCatchPattern":"if err := validateChaincodeQuery(query); err != nil {\n    return fmt.Errorf(\"fix query before sending: %w\", err)\n}\nresp, err := client.Send(ctx, req)\nif err != nil {\n    if strings.Contains(err.Error(), \"at least one chaincode interest\") {\n        return fmt.Errorf(\"interests list was empty; check chaincode config: %w\", err)\n    }\n    return err\n}","preventionTips":["Check that the chaincode name source (config, env, service discovery) is non-empty","Call TestValidateCCQuery in unit tests for any request-builder code","Never construct ChaincodeQuery without explicitly appending at least one interest"],"tags":["discovery","validation","chaincode","fabric","grpc"],"backgroundTag":"empty-required-field","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"}