grafana/k6 · error
not a gRPC client
Error message
not a gRPC client
What it means
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".
Source
Thrown at internal/js/modules/k6/grpc/grpc.go:176
err = s.beginStream(p)
if err != nil {
s.tq.Close()
common.Throw(rt, err)
}
return s.obj
}
// extractClient extracts & validates a grpc.Client from a sobek.Value.
func extractClient(v sobek.Value, rt *sobek.Runtime) (*Client, error) {
if common.IsNullish(v) {
return nil, errors.New("empty gRPC client")
}
client, ok := v.ToObject(rt).Export().(*Client)
if !ok {
return nil, errors.New("not a gRPC client")
}
if client.conn == nil {
return nil, errors.New("no gRPC connection, you must call connect first")
}
return client, nil
}
View on GitHub (pinned to 93accf6570)
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
Example fix
// before
const stream = new grpc.Stream({ addr: 'localhost:8080' }, '/svc/Method');
// after
const client = new grpc.Client();
client.connect('localhost:8080');
const stream = new grpc.Stream(client, '/svc/Method'); Defensive patterns
Strategy: type-guard
Validate before calling
if (!(client instanceof grpc.Client)) { throw new TypeError('expected a grpc.Client instance'); } Type guard
const isGrpcClient = (v) => v instanceof grpc.Client;
Try / catch
try {
const stream = new grpc.Stream(client, method);
} catch (e) {
if (String(e.message).includes('not a gRPC client')) throw new TypeError(`Stream needs a grpc.Client, got ${typeof client}`);
throw e;
} Prevention
- 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
When it happens
Trigger: `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.
Common situations: 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.
Related errors
- empty gRPC client
- k6/experimental/grpc has been graduated, please use k6/net/g
- predicate function is not callable
- no gRPC connection, you must call connect first
- must be an object with key-value pairs
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/34652c189338fb7a.
Report an issue: GitHub.