grafana/k6 · error
lost connection while closing the browser (websocket url: %s
Error message
lost connection while closing the browser (websocket url: %s)
What it means
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.
Source
Thrown at internal/js/modules/k6/browser/common/browser_process.go:105
}
go p.handleClose(ctx)
return &p, nil
}
func (p *BrowserProcess) handleClose(ctx context.Context) {
// If we lose connection to the browser and we're not in-progress with clean
// browser-initiated termination then cancel the context to clean up.
select {
case <-p.lostConnection:
case <-ctx.Done():
}
select {
case <-p.processIsGracefullyClosing:
default:
p.cancel(fmt.Errorf("lost connection while closing the browser (websocket url: %s)", p.wsURL))
}
}
func (p *BrowserProcess) didLoseConnection() {
close(p.lostConnection)
}
func (p *BrowserProcess) isConnected() bool {
var ok bool
select {
case _, ok = <-p.lostConnection:
default:
ok = true
}
return ok
}
// GracefulClose triggers a graceful closing of the browser process.View on GitHub (pinned to 93accf6570)
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.
Example fix
// before
export default async function () {
const page = await browser.newPage();
// ... no explicit close, abrupt exit
}
// after
export default async function () {
const page = await browser.newPage();
try {
// ... test steps
} finally {
await page.close();
}
} Defensive patterns
Strategy: try-catch
Try / catch
try {
await browser.close();
} catch (e) {
if (/lost connection while closing the browser/.test(String(e))) {
// browser already dropped; nothing to close — log and move on
console.warn('browser connection lost during close:', e);
} else {
throw e;
}
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- connection closed with websocket code: %d
- connecting to Chromium over CDP: %w
- sending a message to browser: %w
- WebSocket endpoint cannot be empty
- browser process ended unexpectedly
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/e475d4f5d0772158.
Report an issue: GitHub.