{"record":{"id":"34652c189338fb7a","repo":"grafana/k6","slug":"not-a-grpc-client","errorCode":null,"errorMessage":"not a gRPC client","messagePattern":"not a gRPC client","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/grpc/grpc.go","lineNumber":176,"sourceCode":"\terr = s.beginStream(p)\n\tif err != nil {\n\t\ts.tq.Close()\n\n\t\tcommon.Throw(rt, err)\n\t}\n\n\treturn s.obj\n}\n\n// extractClient extracts & validates a grpc.Client from a sobek.Value.\nfunc extractClient(v sobek.Value, rt *sobek.Runtime) (*Client, error) {\n\tif common.IsNullish(v) {\n\t\treturn nil, errors.New(\"empty gRPC client\")\n\t}\n\n\tclient, ok := v.ToObject(rt).Export().(*Client)\n\tif !ok {\n\t\treturn nil, errors.New(\"not a gRPC client\")\n\t}\n\n\tif client.conn == nil {\n\t\treturn nil, errors.New(\"no gRPC connection, you must call connect first\")\n\t}\n\n\treturn client, nil\n}\n","sourceCodeStart":158,"sourceCodeEnd":185,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/grpc/grpc.go#L158-L185","documentation":"extractClient (internal/js/modules/k6/grpc/grpc.go:174) type-asserts the exported first argument of `new grpc.Stream(...)` to the internal *Client type. \"not a gRPC client\" means a value was passed but it is not an object created by the `grpc.Client` constructor (e.g. a plain object, string, number, or an instance of some other class). The type assertion `v.ToObject(rt).Export().(*Client)` fails and the error is thrown, wrapped as \"invalid GRPC Stream's client: not a gRPC client\".","triggerScenarios":"`new grpc.Stream({}, ...)` (object literal), `new grpc.Stream('localhost:8080', ...)` (passing the address instead of a client), `new grpc.Stream(someOtherObject, ...)`, or wrapping the client in another object/proxy that does not export to *Client.","commonSituations":"Confusing the connect address with the client object; passing a client-like wrapper or mock; refactors that replace the grpc.Client instance with a factory result of the wrong type.","solutions":["Pass the exact object returned by `new grpc.Client()`","If you wrapped the client, unwrap it so the raw grpc.Client instance is the first argument","Do not pass connection strings or config objects where the client is expected"],"exampleFix":"// before\nconst stream = new grpc.Stream({ addr: 'localhost:8080' }, '/svc/Method');\n\n// after\nconst client = new grpc.Client();\nclient.connect('localhost:8080');\nconst stream = new grpc.Stream(client, '/svc/Method');","handlingStrategy":"type-guard","validationCode":"if (!(client instanceof grpc.Client)) { throw new TypeError('expected a grpc.Client instance'); }","typeGuard":"const isGrpcClient = (v) => v instanceof grpc.Client;","tryCatchPattern":"try {\n  const stream = new grpc.Stream(client, method);\n} catch (e) {\n  if (String(e.message).includes('not a gRPC client')) throw new TypeError(`Stream needs a grpc.Client, got ${typeof client}`);\n  throw e;\n}","preventionTips":["Name the variable holding the client explicitly (grpcClient) to avoid passing look-alikes","Never wrap or clone the client object before handing it to grpc.Stream","Centralize Stream creation in one function that takes the client from a single source"],"tags":["grpc","javascript","type-guard","api-misuse"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}