grafana/k6 · error
no gRPC connection, you must call connect first
Error message
no gRPC connection, you must call connect first
What it means
Every client.invoke(method, request) goes through buildInvokeRequest, which first verifies a VU state exists and then that c.conn is set. c.conn is only assigned by a successful client.connect(), so invoking before connecting - or after connect failed - produces this error before the method name is even looked at.
Solutions
- Call client.connect(addr, params) before invoke - it is blocking (no await needed) and returns true on success: const ok = client.connect(addr); if (!ok) throw new Error('connect failed').
- Do the connection once per VU or in setup and guard the invoke path on the connect result.
- If connect is conditional, initialize a flag (let connected = false) and check it before invoking.
Example fix
// before
export default function () {
client.invoke('hello.HelloService/SayHello', { name: 'k6' }); // throws: no gRPC connection
}
// after
export default function () {
client.connect('grpcbin.k6.io:443');
client.invoke('hello.HelloService/SayHello', { name: 'k6' });
} Defensive patterns
Strategy: validation
Validate before calling
// connect() is blocking and returns a boolean - assert it before invoking
const connected = client.connect('grpcbin.k6.io:443');
if (!connected) {
throw new Error(`failed to connect to gRPC server`);
}
client.invoke('hello.HelloService/SayHello', { name: 'k6' }); Try / catch
try {
client.invoke(method, req);
} catch (e) {
if (/must call connect first/.test(e.message)) {
throw new Error('gRPC client not connected - call client.connect() before invoke()');
}
throw e;
} Prevention
- Connect once per VU (or in setup) and store the result in a module-level flag.
- Never swallow connect() exceptions - a silent failure leaves conn nil and every invoke broken.
- Order boilerplate as: load (init) -> connect (setup/VU) -> invoke.
When it happens
Trigger: client.invoke('pkg.Service/Method', req) called before any client.connect(addr); calling invoke when connect() threw and the script swallowed the error with try/catch and continued; or forgetting that connect must complete first in each VU/setup that invokes.
Common situations: Copy-pasting invoke examples while deleting the connect boilerplate; conditional connect logic (if (needsTls) connect()) that skips the call on one branch; error-handling around connect that logs and proceeds, leaving conn nil.
Related errors
- failed to decode PEM key
- method to invoke cannot be empty
- canceled by client (k6)
- encrypted pkcs8 formatted key is not supported
- gRPC exporter endpoint is required
AI-assisted analysis of grafana/k6@8d06114777 (2026-08-18).
Data as JSON: /api/errors/a5afdb5d227bcd33.
Report an issue: GitHub.
Appendix: source
Thrown at internal/js/modules/k6/grpc/client.go:387
}()
return promise, nil
}
// buildInvokeRequest creates a new InvokeRequest from the given method name, request object and parameters
func (c *Client) buildInvokeRequest(
method string,
req sobek.Value,
params sobek.Value,
) (grpcext.InvokeRequest, error) {
grpcReq := grpcext.InvokeRequest{}
state := c.vu.State()
if state == nil {
return grpcReq, common.NewInitContextError("invoking RPC methods in the init context is not supported")
}
if c.conn == nil {
return grpcReq, errors.New("no gRPC connection, you must call connect first")
}
if method == "" {
return grpcReq, errors.New("method to invoke cannot be empty")
}
if method[0] != '/' {
method = "/" + method
}
methodDesc := c.mds[method]
if methodDesc == nil {
return grpcReq, fmt.Errorf("method %q not found in file descriptors", method)
}
p, err := newCallParams(c.vu, params)
if err != nil {
return grpcReq, fmt.Errorf("invalid GRPC's client.invoke() parameters: %w", err)
}
// k6 GRPC Invoke's default timeout is 2 minutesView on GitHub (pinned to 8d06114777)