grafana/k6 · error
invalid WebSocket endpoint %q: host is missing
Error message
invalid WebSocket endpoint %q: host is missing
What it means
Thrown by validateWSEndpoint (called from BrowserType.ConnectOverCDP) when the endpoint has a valid ws/wss scheme but url.Hostname() is empty, i.e. there is no host between 'ws://' and the path. This catches partially-formed CDP URLs such as 'ws:///devtools/browser/<uuid>' before any network dial is attempted, guaranteeing a precise error rather than a DNS/dial failure.
Source
Thrown at internal/js/modules/k6/browser/chromium/browser_type.go:170
// a missing host, etc.) before we attempt to connect.
func validateWSEndpoint(wsEndpoint string) error {
if strings.TrimSpace(wsEndpoint) == "" {
return errors.New("WebSocket endpoint cannot be empty")
}
u, err := url.Parse(wsEndpoint)
if err != nil {
return fmt.Errorf("invalid WebSocket endpoint %q: %w", wsEndpoint, err)
}
if u.Scheme != "ws" && u.Scheme != "wss" {
return fmt.Errorf(
"invalid WebSocket endpoint %q: scheme must be ws or wss, got %q", wsEndpoint, u.Scheme,
)
}
if u.Hostname() == "" {
return fmt.Errorf("invalid WebSocket endpoint %q: host is missing", wsEndpoint)
}
return nil
}
// Connect attaches k6 browser to an existing browser instance.
//
// vuCtx is the context coming from the VU itself. The k6 vu/iteration controls
// its lifecycle.
//
// context.background() is used when connecting to an instance of chromium. The
// connection lifecycle should be handled by the k6 event system.
//
// The separation is important to allow for the iteration to end when k6 requires
// the iteration to end (e.g. during a SIGTERM) and unblocks k6 to then fire off
// the events which allows the connection to close.
func (b *BrowserType) Connect(ctx, vuCtx context.Context, wsEndpoint string) (*common.Browser, error) {
vuCtx, browserOpts, logger, err := b.init(vuCtx, true, k6ext.GetScenarioOpts(b.vu.Context(), b.vu))View on GitHub (pinned to 93accf6570)
Solutions
- Include an explicit host: `ws://127.0.0.1:9222/devtools/browser/<uuid>`
- If the URL is built dynamically, log it before calling connectOverCDP and fix the empty host variable
- Run curl http://<host>:<port>/json/version against the browser and copy the full webSocketDebuggerUrl verbatim
- Add a script-level assertion that the URL matches /^wss?://[^/]+/
Example fix
// before
const endpoint = `ws://${K6_BROWSER_HOST}/devtools/browser/${uuid}`; // K6_BROWSER_HOST unset -> 'ws:///devtools/...'
const browser = chromium.connectOverCDP(endpoint);
// after
const host = __ENV.BROWSER_HOST || '127.0.0.1';
const endpoint = `ws://${host}:9222/devtools/browser/${uuid}`;
const browser = chromium.connectOverCDP(endpoint); Defensive patterns
Strategy: validation
Validate before calling
function buildWsEndpoint(host, port, uuid) {
if (!host) throw new Error('browser host is required');
return `ws://${host}:${port}/devtools/browser/${uuid}`;
}
const endpoint = buildWsEndpoint(__ENV.BROWSER_HOST, __ENV.BROWSER_PORT || '9222', uuid);
if (!/^wss?:\/\/[^\/]+/.test(endpoint)) throw new Error(`bad endpoint: ${endpoint}`); Try / catch
try {
const browser = chromium.connectOverCDP(endpoint);
} catch (e) {
if (String(e.message).includes('host is missing')) {
throw new Error(`BROWSER_HOST env var is empty; endpoint was: ${endpoint}`);
}
throw e;
} Prevention
- Fail fast on empty host variables with an explicit error naming the missing env var
- Log the final endpoint before connecting when it is assembled dynamically
- Unit-test URL builders in CI so empty hosts cannot reach the k6 run
When it happens
Trigger: Calling chromium.connectOverCDP('ws:///devtools/browser/<uuid>') (host omitted, e.g. lost during string templating); building the URL by concatenation where the host variable is empty: `ws://${host}/devtools/...` with host unset; passing 'ws://:9222' (port without host).
Common situations: Endpoint assembled from environment variables where the host variable is missing or misspelled; CI pipelines that inject the WS path but not the host; scripts copied between environments where the host placeholder was never substituted.
Related errors
- invalid WebSocket endpoint %q: scheme must be ws or wss, got
- WebSocket endpoint cannot be empty
- connecting to Chromium over CDP: %w
- connecting to browser: %w
- connecting to browser DevTools URL: %w
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/7b40cfb6742ef9cd.
Report an issue: GitHub.