grafana/k6 · error
connection closed with websocket code: %d
Error message
connection closed with websocket code: %d
What it means
Connection.close records the websocket close code as the cancel cause for the connection context, so every pending or future operation on that connection fails with this message via ContextErr. The %d is the RFC 6455 close code: 1000/1001 are orderly shutdowns, 1006 means an abnormal drop (no close frame), others indicate protocol-level failures.
Source
Thrown at internal/js/modules/k6/browser/common/connection.go:201
errorCh: make(chan error),
done: make(chan struct{}),
closing: make(chan struct{}),
msgIDGen: &msgID{},
sessions: make(map[target.SessionID]*Session),
onTargetAttachedToTarget: onTargetAttachedToTarget,
}
go c.recvLoop()
go c.sendLoop()
return &c, nil
}
func (c *Connection) close(code int) error {
c.logger.Debugf("Connection:close", "code:%d", code)
defer func() {
c.cancelCtx(fmt.Errorf("connection closed with websocket code: %d", code))
}()
var err error
c.shutdownOnce.Do(func() {
defer func() {
// Stop the main control loop
close(c.done)
_ = c.conn.Close()
}()
c.closeAllSessions()
err = c.conn.WriteControl(websocket.CloseMessage,
websocket.FormatCloseMessage(code, ""),
time.Now().Add(time.Second),
)
// According to the WS RFC[1], we might want to wait for a responseView on GitHub (pinned to 93accf6570)
Solutions
- Map the code: 1000/1001 = expected shutdown (usually harmless if during teardown); 1006 = crash/network drop worth investigating.
- Await all pending operations (await page.goto(...)) before closing pages/browser so nothing races the close.
- For 1006, check the browser process lifetime and memory limits — it was killed or dropped.
- Move cleanup into the iteration teardown and guard it so a normal close cannot interrupt in-flight work.
Example fix
// before page.goto(url); // not awaited await browser.close(); // races the navigation // after await page.goto(url); // fully awaited await browser.close();
Defensive patterns
Strategy: try-catch
Try / catch
try {
await page.evaluate('1+1');
} catch (e) {
const m = String(e).match(/connection closed with websocket code: (\d+)/);
if (m) {
const code = Number(m[1]);
if (code === 1000 || code === 1001) {
// orderly shutdown (test teardown) — ignore
} else {
// abnormal close (e.g. 1006): browser crashed or connection dropped — investigate
console.error('abnormal websocket close', code);
}
} else {
throw e;
}
} Prevention
- Await every browser operation before closing pages/browser to avoid racing the close.
- Treat 1006 as a browser-crash signal: check process logs and memory, not the k6 script.
- Keep teardown idempotent so double-close paths cannot surprise in-flight calls.
When it happens
Trigger: Browser (or target) closes the websocket during a CDP call: browser.Close(), page/target destroyed, browser crash (1006), or k6 itself closing the connection after receiving a close frame — the code then propagates to all in-flight sends/waits.
Common situations: Test tears down while a navigation or evaluation is still pending; chromium crashes mid-run; remote browser restarted under k6; the code appearing repeatedly in logs usually means an operation raced the close instead of being awaited first.
Understand the failure class
- Connection failures: ECONNREFUSED, ECONNRESET, and friends — why connections get refused, reset, or dropped.
Related errors
- lost connection while closing the browser (websocket url: %s
- connecting to Chromium over CDP: %w
- sending a message to browser: %w
- closing communication with browser: %w
- WebSocket endpoint cannot be empty
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/00c7d1bf10e33547.
Report an issue: GitHub.