{"record":{"id":"c39b7f8e3bdb0d37","repo":"hyperledger/fabric","slug":"access-denied-client-identity-wasn-t-supplied","errorCode":null,"errorMessage":"access denied, client identity wasn't supplied","messagePattern":"access denied, client identity wasn't supplied","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"discovery/service.go","lineNumber":245,"sourceCode":"\t\t}\n\t}\n\treturn peersByOrg\n}\n\n// validateStructure validates that the request contains all the needed fields and that they are computed correctly\nfunc validateStructure(ctx context.Context, request *discovery.SignedRequest, tlsEnabled bool, certHashFromContext certHashExtractor) (*discovery.Request, error) {\n\tif request == nil {\n\t\treturn nil, errors.New(\"nil request\")\n\t}\n\treq, err := protoext.SignedRequestToRequest(request)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"failed parsing request\")\n\t}\n\tif req.Authentication == nil {\n\t\treturn nil, errors.New(\"access denied, no authentication info in request\")\n\t}\n\tif len(req.Authentication.ClientIdentity) == 0 {\n\t\treturn nil, errors.New(\"access denied, client identity wasn't supplied\")\n\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 {","sourceCodeStart":227,"sourceCodeEnd":263,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/discovery/service.go#L227-L263","documentation":"This error is returned by the discovery service's validateStructure when a client submits a discovery request whose Authentication section either has an empty ClientIdentity field or no Authentication at all is impossible — here specifically the Authentication object exists but ClientIdentity is empty. The discovery service requires the caller to identify itself so the server can authorize the request.","triggerScenarios":"Calling the Discover or TestValidateStructure RPC with a request where req.Authentication is non-nil but req.Authentication.ClientIdentity is an empty byte slice.","commonSituations":"Client SDK misconfiguration where the identity/credential material (e.g. an enrollment certificate or serialized identity) failed to load silently; constructing a discovery.Request by hand without populating Auth; upgrading an SDK and losing the identity config field.","solutions":["Populate req.Authentication.ClientIdentity with the client's serialized identity (e.g. x509 certificate bytes) before sending the discovery request","Verify the client config/credential loading path actually returns the identity and is not silently empty","Use a maintained SDK (e.g. fabric-sdk-go) that sets authentication automatically from the signing identity","Test locally with TestValidateStructure to confirm the request passes structural validation before connecting"],"exampleFix":"// before\nreq := &discovery.Request{Authentication: &discovery.AuthInfo{}}\n// after\nreq := &discovery.Request{Authentication: &discovery.AuthInfo{ClientIdentity: serializedIdentity}}","handlingStrategy":"validation","validationCode":"func validateAuth(req *discovery.Request) error {\n    if req.Authentication == nil || len(req.Authentication.ClientIdentity) == 0 {\n        return errors.New(\"discovery request requires a non-empty ClientIdentity\")\n    }\n    return nil\n}","typeGuard":"func hasClientIdentity(req *discovery.Request) bool {\n    return req != nil && req.Authentication != nil && len(req.Authentication.ClientIdentity) > 0\n}","tryCatchPattern":"resp, err := client.Send(ctx, req)\nif err != nil {\n    if strings.Contains(err.Error(), \"client identity wasn't supplied\") {\n        return fmt.Errorf(\"populating ClientIdentity and retrying: %w\", reloadIdentityAndSend())\n    }\n    return err\n}","preventionTips":["Always derive the AuthInfo from a loaded signing identity, never hand-build an empty Authentication","Log identity length at client startup to confirm credentials loaded","Validate the request with TestValidateStructure before sending in tests"],"tags":["discovery","authentication","fabric","grpc"],"backgroundTag":"missing-client-identity","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"}