{"record":{"id":"e475d4f5d0772158","repo":"grafana/k6","slug":"lost-connection-while-closing-the-browser-websock","errorCode":null,"errorMessage":"lost connection while closing the browser (websocket url: %s)","messagePattern":"lost connection while closing the browser \\(websocket url: (.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/browser_process.go","lineNumber":105,"sourceCode":"\t}\n\n\tgo p.handleClose(ctx)\n\n\treturn &p, nil\n}\n\nfunc (p *BrowserProcess) handleClose(ctx context.Context) {\n\t// If we lose connection to the browser and we're not in-progress with clean\n\t// browser-initiated termination then cancel the context to clean up.\n\tselect {\n\tcase <-p.lostConnection:\n\tcase <-ctx.Done():\n\t}\n\n\tselect {\n\tcase <-p.processIsGracefullyClosing:\n\tdefault:\n\t\tp.cancel(fmt.Errorf(\"lost connection while closing the browser (websocket url: %s)\", p.wsURL))\n\t}\n}\n\nfunc (p *BrowserProcess) didLoseConnection() {\n\tclose(p.lostConnection)\n}\n\nfunc (p *BrowserProcess) isConnected() bool {\n\tvar ok bool\n\tselect {\n\tcase _, ok = <-p.lostConnection:\n\tdefault:\n\t\tok = true\n\t}\n\treturn ok\n}\n\n// GracefulClose triggers a graceful closing of the browser process.","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/grafana/k6/blob/93accf6570dcd306ca5e99cc44c393ee3797761b/internal/js/modules/k6/browser/common/browser_process.go#L87-L123","documentation":"BrowserProcess.handleClose waits on lostConnection or context completion; if the websocket to the browser dropped and the graceful, browser-initiated shutdown flag was NOT set, it cancels the process context with this error. It usually surfaces as the cause appended by ContextErr on any in-flight browser operation.","triggerScenarios":"The browser process crashes or its DevTools websocket drops while k6 is shutting the browser down (or mid-test), without k6 having initiated a clean Browser.close. The lostConnection channel fires, processIsGracefullyClosing is empty, so cancel() injects this cause.","commonSituations":"Chrome/Chromium killed by the OS (OOM killer), container runtime killing the browser at test end, remote browser (K6_BROWSER_REMOTE_URL) dropping the connection, version mismatch between k6's CDP layer and an exotic Chromium build.","solutions":["Inspect browser-side logs (run with K6_BROWSER_ENABLE_DEBUGGING=true and capture stderr) for the crash reason.","If the browser is OOM-killed, raise container/host memory or reduce parallel browser scenarios.","Ensure browser.close() is reached in the script (wrap test body so teardown always runs) so shutdown is graceful rather than connection-loss-driven.","Upgrade k6 so its CDP protocol version matches your Chromium build."],"exampleFix":"// before\nexport default async function () {\n  const page = await browser.newPage();\n  // ... no explicit close, abrupt exit\n}\n\n// after\nexport default async function () {\n  const page = await browser.newPage();\n  try {\n    // ... test steps\n  } finally {\n    await page.close();\n  }\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await browser.close();\n} catch (e) {\n  if (/lost connection while closing the browser/.test(String(e))) {\n    // browser already dropped; nothing to close — log and move on\n    console.warn('browser connection lost during close:', e);\n  } else {\n    throw e;\n  }\n}","preventionTips":["Always close pages/browser in try/finally so shutdown is browser-initiated and graceful.","Monitor browser memory in containers to preempt OOM kills of chromium.","Keep k6 and Chromium versions roughly in sync; pin a known-good browser image."],"tags":["browser","websocket","shutdown","process","connection"],"backgroundTag":null,"analyzedSha":"93accf6570dcd306ca5e99cc44c393ee3797761b","analyzedAt":"2026-08-15T21:23:27.118Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}