{"record":{"id":"c068f20e1cc61f26","repo":"grafana/k6","slug":"connecting-to-browser-w","errorCode":null,"errorMessage":"connecting to browser: %w","messagePattern":"connecting to browser: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/chromium/browser_type.go","lineNumber":210,"sourceCode":"\n\tbp, err := b.connect(ctx, vuCtx, 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\nfunc (b *BrowserType) connect(\n\tctx, vuCtx context.Context, wsURL string, opts *common.BrowserOptions, logger *log.Logger,\n) (*common.Browser, error) {\n\tbrowserProc, err := b.link(ctx, wsURL, logger)\n\tif browserProc == nil {\n\t\treturn nil, fmt.Errorf(\"connecting to browser: %w\", err)\n\t}\n\n\t// If this context is cancelled we'll initiate an extension wide\n\t// cancellation and shutdown.\n\tbrowserCtx, browserCtxCancel := context.WithCancel(vuCtx)\n\tb.Ctx = browserCtx\n\tbrowser, err := common.NewBrowser(\n\t\tctx, browserCtx, browserCtxCancel, browserProc, opts, logger,\n\t)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"connecting to browser: %w\", err)\n\t}\n\n\treturn browser, nil\n}\n\nfunc (b *BrowserType) link(\n\tctx context.Context,","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/chromium/browser_type.go#L192-L228","documentation":"Returned by BrowserType.connect when link() cannot establish the remote browser process: common.NewRemoteBrowserProcess fails to dial the WebSocket endpoint, so browserProc is nil and the dial error is wrapped as 'connecting to browser'. Callers of Connect/ConnectOverCDP additionally wrap it in k6ext.UserFriendlyError, which hints at timeout causes. This is the generic 'cannot reach the remote Chrome over CDP' failure.","triggerScenarios":"chromium.connect()/connectOverCDP() to an endpoint where Chrome is not listening (wrong port, process not started); firewall or network partition between k6 and the remote browser; endpoint requires auth/TLS and the handshake is rejected; the remote Chrome exited between discovery and connect; dial exceeds K6_BROWSER_TIMEOUT.","commonSituations":"Remote browser container (e.g. browserless/chrome) not ready yet when the test starts; k8s Service name typo; connecting to a ws:// endpoint served only over TLS (needs wss://); Chrome started without --remote-debugging-port; UserFriendlyError text pointing at a too-small K6_BROWSER_TIMEOUT on slow CI machines.","solutions":["Verify the browser is reachable: curl http://<host>:<port>/json/version from the same host/container k6 runs on","If the error mentions timeout, raise K6_BROWSER_TIMEOUT (e.g. export K6_BROWSER_TIMEOUT=60s) for slow remote setups","Ensure Chrome was started with --remote-debugging-port=<port> and, for remote/non-localhost setups, the appropriate --remote-debugging-address","Match the scheme to the transport: wss:// for TLS endpoints, ws:// for plain","Add a readiness wait/retry loop around connectOverCDP when the browser container starts in parallel with the test"],"exampleFix":"// before\nconst browser = chromium.connectOverCDP('ws://browserless:3000');\n\n// after\nlet browser;\nfor (let i = 0; i < 5; i++) {\n  try { browser = chromium.connectOverCDP('ws://browserless:3000'); break; }\n  catch (e) { sleep(3); }\n}\nif (!browser) throw new Error('browser not reachable after retries');","handlingStrategy":"retry","validationCode":"// Pre-flight the browser's HTTP endpoint before dialing the WS one\nimport http from 'k6/http';\nfunction browserReady(host, port, timeoutMs = 30000) {\n  const deadline = Date.now() + timeoutMs;\n  while (Date.now() < deadline) {\n    const r = http.get(`http://${host}:${port}/json/version`, { timeout: '2s' });\n    if (r.status === 200) return r.json('webSocketDebuggerUrl');\n    sleep(2);\n  }\n  throw new Error(`browser at ${host}:${port} not ready`);\n}\nconst wsUrl = browserReady(__ENV.BROWSER_HOST, __ENV.BROWSER_PORT);","typeGuard":null,"tryCatchPattern":"let browser;\nfor (let attempt = 0; attempt < 3; attempt++) {\n  try {\n    browser = chromium.connectOverCDP(wsUrl);\n    break;\n  } catch (e) {\n    const m = String(e.message);\n    if (attempt < 2 && (m.includes('connecting to browser') || m.includes('timed out'))) {\n      sleep(3);\n      continue;\n    }\n    throw e;\n  }\n}","preventionTips":["Gate the test on a readiness probe of /json/version before connecting","Set K6_BROWSER_TIMEOUT high enough for remote/containerized browsers","Ensure Chrome is started with --remote-debugging-port and reachable from the k6 network"],"tags":["network","websocket","cdp","connect","timeout"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}