grafana/k6 · error

couldn't parse cloud logs host %w

Error message

couldn't parse cloud logs host %w

What it means

Cloud log tailing (cloudapi/logs.go) opens a websocket to Config.LogsTailURL - default wss://cloudlogs.k6.io/api/v1/tail, overridable via K6_CLOUD_LOGS_TAIL_URL (cloudapi/config.go:30). Before connecting it url.Parse's the value; a parse failure aborts log tailing with this wrapped error. url.Parse only fails on structurally invalid URLs, so this almost always means a bad override value rather than a transient problem.

Source

Thrown at cloudapi/logs.go:91

	}

	return ts
}

func labelsToLogrusFields(labels map[string]string) logrus.Fields {
	fields := make(logrus.Fields, len(labels))

	for key, val := range labels {
		fields[key] = val
	}

	return fields
}

func (c *Config) logtailConn(ctx context.Context, referenceID string, since time.Time) (*websocket.Conn, error) {
	u, err := url.Parse(c.LogsTailURL.String)
	if err != nil {
		return nil, fmt.Errorf("couldn't parse cloud logs host %w", err)
	}

	u.RawQuery = fmt.Sprintf(`query={test_run_id="%s"}&start=%d`, referenceID, since.UnixNano())

	headers := make(http.Header)
	headers.Add("Authorization", "token "+c.Token.String)
	headers.Add("X-K6testrun-Id", referenceID)

	var conn *websocket.Conn
	err = retry(sleeperFunc(time.Sleep), 3, 5*time.Second, 2*time.Minute, func() (err error) {
		// We don't need to close the http body or use it for anything until we want to actually log
		// what the server returned as body when it errors out
		conn, _, err = websocket.DefaultDialer.DialContext(ctx, u.String(), headers) //nolint:bodyclose
		return err
	})
	if err != nil {
		return nil, err
	}

View on GitHub (pinned to 93accf6570)

Solutions

  1. Unset K6_CLOUD_LOGS_TAIL_URL to fall back to the default wss://cloudlogs.k6.io/api/v1/tail
  2. Fix the value to a full absolute URL with scheme and, if non-default, port: wss://host:8443/api/v1/tail
  3. Strip whitespace/quotes from the env value in CI before launching k6

Example fix

# before
export K6_CLOUD_LOGS_TAIL_URL='cloudlogs.internal:443/api/v1/tail'   # no scheme

# after
export K6_CLOUD_LOGS_TAIL_URL='wss://cloudlogs.internal:443/api/v1/tail'
Defensive patterns

Strategy: validation

Validate before calling

# reject malformed log-tail URLs before the run
python3 - <<'EOF'
from urllib.parse import urlparse
import os, sys
u = os.environ.get('K6_CLOUD_LOGS_TAIL_URL', 'wss://cloudlogs.k6.io/api/v1/tail')
p = urlparse(u)
assert p.scheme in ('ws', 'wss') and p.hostname, f'bad K6_CLOUD_LOGS_TAIL_URL: {u!r}'
EOF

Prevention

When it happens

Trigger: K6_CLOUD_LOGS_TAIL_URL containing spaces or control characters, a missing scheme ('cloudlogs.k6.io/api/v1/tail'), or an invalid port ('wss://host:port'); a CI template or orchestrator injecting a mangled value.

Common situations: Custom log-tail endpoints for self-hosted setups specified without the ws:// or wss:// scheme; trailing whitespace or quotes around the env value; YAML/CI interpolation artifacts.

Related errors


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