{"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/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/chromium/browser_type.go#L137-L173","documentation":"Before k6 attaches to an existing browser over CDP, validateWSEndpoint sanity-checks the WebSocket URL: it must be non-empty after trimming, parse as a URL, and use the ws:// or wss:// scheme (other failures give their own messages). This specific error means the wsEndpoint value resolved to an empty or whitespace-only string, so connecting would be meaningless.","triggerScenarios":"Setting K6_BROWSER_WS_ENDPOINT to an empty value or spaces; building the endpoint from an env var that is not set in this shell/CI step (expands to empty); copying a config template where the endpoint placeholder was never filled in.","commonSituations":"CI pipelines where the env var is defined in one job but used in another; docker-compose/service definitions with empty-string defaults; scripts that export the endpoint conditionally and skip it on some branches.","solutions":["Set a real CDP WebSocket endpoint: K6_BROWSER_WS_ENDPOINT=ws://localhost:9222/devtools/browser/<id> — get the id from curl http://localhost:9222/json/version when Chrome runs with --remote-debugging-port=9222","Make sure the variable is exported in the same shell/step that runs k6 (print it masked in CI logs to confirm it is set)","Trim accidental whitespace/quotes in the value; a quoted value with stray spaces trips the trim check"],"exampleFix":"# before\nexport K6_BROWSER_WS_ENDPOINT=\"\"\nk6 run script.js\n\n# after\ngoogle-chrome --remote-debugging-port=9222 &\nexport K6_BROWSER_WS_ENDPOINT=\"$(curl -s http://localhost:9222/json/version | jq -r .webSocketDebuggerUrl)\"\nk6 run script.js","handlingStrategy":"validation","validationCode":"const endpoint = (process.env.K6_BROWSER_WS_ENDPOINT ?? '').trim();\nif (!endpoint) {\n  throw new Error('K6_BROWSER_WS_ENDPOINT is empty — start Chrome with --remote-debugging-port and set the ws URL');\n}\nif (!/^wss?:\\/\\//.test(endpoint)) {\n  throw new Error('K6_BROWSER_WS_ENDPOINT must start with ws:// or wss://');\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Fetch the endpoint programmatically: curl http://localhost:9222/json/version gives webSocketDebuggerUrl","Assert required env vars in a CI preflight step before invoking k6","Avoid empty-string defaults for the env var in compose/CI templates"],"tags":["browser","cdp","websocket","environment","configuration"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}