grafana/k6 · error

empty gRPC client

Error message

empty gRPC client

What it means

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.

Source

Thrown at internal/js/modules/k6/grpc/grpc.go:171

		tagsAndMeta:    &p.TagsAndMeta,
	}

	defineStream(rt, s)

	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 a `new grpc.Client()` instance as the first argument: `new grpc.Stream(client, method, params)`
  2. Check that the client variable is defined at the call site (typo/scoping bug)
  3. Make sure `client.connect(addr)` was called before constructing the Stream

Example fix

// before
const stream = new grpc.Stream(null, '/hello.HelloService/SayHello');

// after
const client = new grpc.Client();
client.connect('grpcbin.test-loadimpact.com:443');
const stream = new grpc.Stream(client, '/hello.HelloService/SayHello');
Defensive patterns

Strategy: type-guard

Validate before calling

if (!client) { throw new Error('gRPC client is not initialized'); }

Type guard

const isGrpcClient = (v) => !!v && v instanceof grpc.Client;

Try / catch

try {
  const stream = new grpc.Stream(client, method);
} catch (e) {
  if (String(e.message).includes('empty gRPC client')) throw new Error('Stream created before a client was passed');
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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