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

  1. Pass the exact object returned by `new grpc.Client()`
  2. If you wrapped the client, unwrap it so the raw grpc.Client instance is the first argument
  3. 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

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


AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15). Data as JSON: /api/errors/34652c189338fb7a. Report an issue: GitHub.