grafana/k6 · error

failed to create a new stream: %w

Error message

failed to create a new stream: %w

What it means

Thrown by k6's gRPC streaming API when client.newStream(method, params) cannot establish the underlying gRPC stream. beginStream (internal/js/modules/k6/grpc/stream.go:99-102) calls conn.NewStream with the VU context (wrapped in a context.WithTimeout if a params.timeout was given) and wraps any failure with %w, so the tail of the message carries the real grpc-go cause (connection refused, TLS handshake error, unavailable, deadline exceeded, etc.).

Source

Thrown at internal/js/modules/k6/grpc/stream.go:101

		Method:                 s.method,
		MethodDescriptor:       s.methodDescriptor,
		DiscardResponseMessage: p.DiscardResponseMessage,
		TagsAndMeta:            &p.TagsAndMeta,
		Metadata:               p.Metadata,
	}

	ctx := s.vu.Context()
	var cancel context.CancelFunc

	if p.Timeout != time.Duration(0) {
		ctx, cancel = context.WithTimeout(ctx, p.Timeout)
	}

	s.timeoutCancel = cancel

	stream, err := s.client.conn.NewStream(ctx, *req)
	if err != nil {
		return fmt.Errorf("failed to create a new stream: %w", err)
	}
	s.stream = stream
	metrics.PushIfNotDone(s.vu.Context(), s.vu.State().Samples, metrics.Sample{
		TimeSeries: metrics.TimeSeries{
			Metric: s.instanceMetrics.Streams,
			Tags:   s.tagsAndMeta.Tags,
		},
		Time:     time.Now(),
		Metadata: s.tagsAndMeta.Metadata,
		Value:    1,
	})

	go s.loop()

	return nil
}

func (s *stream) loop() {

View on GitHub (pinned to 93accf6570)

Solutions

  1. Read the wrapped cause after the colon: 'connection refused' means address/port; 'authentication handshake failed' or 'x509' means TLS config; 'deadline exceeded' means params.timeout.
  2. Verify the server with a plain client.invoke() call — if invoke also fails, the problem is in connect(), not the stream.
  3. For TLS servers, align connect params: remove plaintext:true, add tls: { cacerts: ... } (and cert/key for mTLS).
  4. Increase the stream timeout: client.newStream(method, { timeout: '30s' }) or set connect timeout.
  5. Confirm the method string exactly matches the proto service path and that the method is a server/client streaming RPC.

Example fix

// before
client.connect('grpc.example.com:443', { plaintext: true });
const stream = client.newStream('chat.ChatService/Connect'); // failed to create a new stream: ... handshake failure

// after
client.connect('grpc.example.com:443', { tls: { cacerts: [caPem] } });
const stream = client.newStream('chat.ChatService/Connect', { timeout: '30s' });
Defensive patterns

Strategy: try-catch

Validate before calling

// Cheap connectivity pre-check is not possible for gRPC streams; validate configuration instead.
function assertStreamConfig(client, method) {
  if (!method.startsWith('/') || method.split('/').length !== 3) throw new Error(`invalid gRPC method '${method}', expected '/pkg.Service/Method'`);
}

Try / catch

try {
  const stream = client.newStream('/svc.Method/stream', { timeout: '30s' });
  stream.on('error', (e) => console.log(`stream error: ${e}`));
} catch (err) {
  const cause = String(err.message).split(':').pop().trim();
  if (/refused|unavailable/.test(cause)) { /* server down: record failure, abort scenario */ }
  else if (/handshake|x509/.test(cause)) { /* TLS config: fix connect params */ }
  else if (/deadline/.test(cause)) { /* raise timeout and retry once */ }
}

Prevention

When it happens

Trigger: Server is down or the address/port is wrong (rpc error: connection refused); TLS mismatch — e.g. connecting with plaintext:true to a TLS endpoint or vice versa; calling newStream before a successful client.connect(); a params.timeout that expires during stream setup (context deadline exceeded); the method name not matching a loaded service (stream mode on a method that is not a streaming RPC).

Common situations: Load testing a staging gRPC service that requires mTLS (missing tls.cert/key in connect params); typo in the method string ('/pkg.Service/Method' format); server behind a proxy that breaks HTTP/2; timeout set too low for slow TLS handshakes; reusing a client whose connection was closed after a prior error.

Related errors


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