{"record":{"id":"cff5f40986a331f7","repo":"grafana/k6","slug":"empty-grpc-client","errorCode":null,"errorMessage":"empty gRPC client","messagePattern":"empty gRPC client","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/grpc/grpc.go","lineNumber":171,"sourceCode":"\t\ttagsAndMeta:    &p.TagsAndMeta,\n\t}\n\n\tdefineStream(rt, s)\n\n\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":153,"sourceCodeEnd":185,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/grpc/grpc.go#L153-L185","documentation":"k6's gRPC module validates the first argument of the `new grpc.Stream(client, method, params)` constructor via the internal extractClient helper (internal/js/modules/k6/grpc/grpc.go:169). \"empty gRPC client\" means the value passed as the client was null or undefined, so there is no client object to build the stream on. The Stream constructor wraps it as \"invalid GRPC Stream's client: empty gRPC client\" and throws, aborting the iteration.","triggerScenarios":"Calling `new grpc.Stream()` with no arguments, or `new grpc.Stream(null, '/pkg.Service/Method')` / `new grpc.Stream(undefined, ...)` — i.e. the first argument is nullish.","commonSituations":"Refactoring where the client variable is out of scope or misspelled; copy-pasting examples written for the older synchronous `grpc.invoke` API into the newer Stream API and forgetting the client argument; conditional code paths that leave the client variable undefined.","solutions":["Pass a `new grpc.Client()` instance as the first argument: `new grpc.Stream(client, method, params)`","Check that the client variable is defined at the call site (typo/scoping bug)","Make sure `client.connect(addr)` was called before constructing the Stream"],"exampleFix":"// before\nconst stream = new grpc.Stream(null, '/hello.HelloService/SayHello');\n\n// after\nconst client = new grpc.Client();\nclient.connect('grpcbin.test-loadimpact.com:443');\nconst stream = new grpc.Stream(client, '/hello.HelloService/SayHello');","handlingStrategy":"type-guard","validationCode":"if (!client) { throw new Error('gRPC client is not initialized'); }","typeGuard":"const isGrpcClient = (v) => !!v && v instanceof grpc.Client;","tryCatchPattern":"try {\n  const stream = new grpc.Stream(client, method);\n} catch (e) {\n  if (String(e.message).includes('empty gRPC client')) throw new Error('Stream created before a client was passed');\n  throw e;\n}","preventionTips":["Always create and connect the client in one helper function so the Stream call site always receives a live client","Lint for `new grpc.Stream(` with fewer than 2 arguments","Keep client construction in init or at the top of the iteration, never conditionally without a default"],"tags":["grpc","javascript","validation","api-misuse"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}