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

  1. 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').
  2. Do the connection once per VU or in setup and guard the invoke path on the connect result.
  3. 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

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


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 minutes

View on GitHub (pinned to 8d06114777)