{"record":{"id":"20375e15a7ad9f9f","repo":"grafana/k6","slug":"websocket-endpoint-cannot-be-empty","errorCode":null,"errorMessage":"WebSocket endpoint cannot be empty","messagePattern":"WebSocket endpoint cannot be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/chromium/browser_type.go","lineNumber":155,"sourceCode":"\n\tbp, err := b.connect(ctx, ctx, wsEndpoint, browserOpts, logger)\n\tif err != nil {\n\t\terr = &k6ext.UserFriendlyError{\n\t\t\tErr:     err,\n\t\t\tTimeout: browserOpts.Timeout,\n\t\t}\n\t\treturn nil, fmt.Errorf(\"%w\", err)\n\t}\n\n\treturn bp, nil\n}\n\n// validateWSEndpoint returns an error if wsEndpoint is not a usable CDP\n// WebSocket URL, catching common mistakes (an empty value, a non-ws scheme,\n// a missing host, etc.) before we attempt to connect.\nfunc validateWSEndpoint(wsEndpoint string) error {\n\tif strings.TrimSpace(wsEndpoint) == \"\" {\n\t\treturn errors.New(\"WebSocket endpoint cannot be empty\")\n\t}\n\n\tu, err := url.Parse(wsEndpoint)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"invalid WebSocket endpoint %q: %w\", wsEndpoint, err)\n\t}\n\n\tif u.Scheme != \"ws\" && u.Scheme != \"wss\" {\n\t\treturn fmt.Errorf(\n\t\t\t\"invalid WebSocket endpoint %q: scheme must be ws or wss, got %q\", wsEndpoint, u.Scheme,\n\t\t)\n\t}\n\n\tif u.Hostname() == \"\" {\n\t\treturn fmt.Errorf(\"invalid WebSocket endpoint %q: host is missing\", wsEndpoint)\n\t}\n\n\treturn nil","sourceCodeStart":137,"sourceCodeEnd":173,"githubUrl":"https://github.com/grafana/k6/blob/8d06114777191d21ef885d05c5f8aa9e1ed838ae/internal/js/modules/k6/browser/chromium/browser_type.go#L137-L173","documentation":"Before connecting to a remote Chromium over CDP, k6 validates the WebSocket URL in validateWSEndpoint (internal/js/modules/k6/browser/chromium/browser_type.go:155). An empty or whitespace-only value fails immediately with this error instead of attempting a doomed connection. The value comes from the K6_BROWSER_WS_URL environment variable (or the wsURL browser option).","triggerScenarios":"Running with K6_BROWSER_WS_URL defined but empty (K6_BROWSER_WS_URL= k6 run script.js), a whitespace-only value, CI defining the variable with no value, or a docker -e K6_BROWSER_WS_URL flag without an argument; a programmatic BrowserConfig with wsURL left \"\" while remote connection is selected.","commonSituations":"CI secrets/variables not populated for the job; docker-compose files where the env var is declared but the service URL is commented out; shell expansion of an unset variable ($REMOTE_WS expanding to empty); switching a pipeline from local to remote browser without updating values.","solutions":["Provide a real CDP URL, e.g. K6_BROWSER_WS_URL='ws://localhost:9222/devtools/browser/<guid>'","Fetch the endpoint from the browser's HTTP discovery API: curl http://host:9222/json/version and use its webSocketDebuggerUrl","Unset the variable entirely if you want k6 to launch a local browser instead of connecting remotely","Audit CI env plumbing for empty expansions (use ${VAR:?VAR required} in shells to fail fast)"],"exampleFix":"# before\nK6_BROWSER_WS_URL= k6 run script.js\n\n# after\nK6_BROWSER_WS_URL=\"$(curl -s http://localhost:9222/json/version | jq -r .webSocketDebuggerUrl)\" k6 run script.js","handlingStrategy":"validation","validationCode":"# fail fast in the shell before invoking k6\nif [ -z \"${K6_BROWSER_WS_URL// /}\" ]; then\n  echo \"K6_BROWSER_WS_URL is empty — set it to ws://host:9222/devtools/browser/<guid> or unset it for a local browser\" >&2\n  exit 1\nfi\nk6 run script.js","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use ${VAR:?message} expansion in shells so an unset/empty ws URL aborts immediately","Fetch webSocketDebuggerUrl from http://host:9222/json/version instead of hand-writing the guid","In CI, add a pre-run step that curls the browser's /json/version endpoint as a healthcheck","Prefer K6_BROWSER_HEADLESS and ws settings in one place (env file) over scattered flags"],"tags":["browser","websocket","cdp","remote-browser","environment-variables","configuration"],"backgroundTag":"invalid-websocket-url","analyzedSha":"8d06114777191d21ef885d05c5f8aa9e1ed838ae","analyzedAt":"2026-08-18T03:05:52.393Z","contentChangedAt":"2026-08-18T03:05:52.393Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}