grafana/k6 · error
default browser context can't be closed
Error message
default browser context can't be closed
What it means
BrowserContext.Close() refuses to close Chromium's default browser context, which is represented internally by an empty context ID. The check happens before any CDP call: Target.disposeBrowserContext cannot be applied to the default context, so k6 rejects it locally. Only contexts you created with browser.newContext() can be closed.
Solutions
- Create your own context with browser.newContext() and use that instead of the default one
- Remove the close() call for the default context — k6 closes it automatically when the browser shuts down
- Audit cleanup code so it only closes contexts it created
Example fix
// before const ctx = browser.context(); // default browser context ctx.close(); // throws: default browser context can't be closed // after const ctx = browser.newContext(); const page = ctx.newPage(); // ... ctx.close(); // user-created context, closes fine
Defensive patterns
Strategy: validation
Validate before calling
// only close contexts you created with browser.newContext() const ctx = browser.newContext(); // ... use ctx ... if (ctx) ctx.close(); // safe: user-created context
Try / catch
try {
ctx.close();
} catch (e) {
if (String(e.message).includes("default browser context can't be closed")) {
// expected when handed the default context: skip and let k6 clean it up
console.warn('skipped close of default browser context');
} else {
throw e;
}
} Prevention
- Never call close() on the context from browser.context()/default context
- Audit cleanup helpers so they only close contexts created by browser.newContext()
- k6 closes the default context automatically at browser shutdown
When it happens
Trigger: Calling close() on the default context — e.g. const ctx = browser.context() (older k6 API) or any handle to the browser's default context — then ctx.close().
Common situations: Scripts written for older k6 versions where browser.context() returned the default context; generic 'close everything I touched' cleanup loops that include the default context; porting Playwright code where browser.defaultContext() exists.
Related errors
- disposing browser context
- adding init script to browser context
- browser is closing
- clearing permissions
- cookie name must be set: %#v
AI-assisted analysis of grafana/k6@01ffac6f24 (2026-08-18).
Data as JSON: /api/errors/4e49dd7feaffdfae.
Report an issue: GitHub.
Appendix: source
Thrown at internal/js/modules/k6/browser/common/browser_context.go:210
// ClearPermissions clears any permission overrides.
func (b *BrowserContext) ClearPermissions() error {
b.logger.Debugf("BrowserContext:ClearPermissions", "bctxid:%v", b.id)
action := cdpbrowser.ResetPermissions().WithBrowserContextID(b.id)
if err := action.Do(cdp.WithExecutor(b.ctx, b.browser.conn)); err != nil {
return fmt.Errorf("clearing permissions: %w", err)
}
return nil
}
// Close shuts down the browser context.
func (b *BrowserContext) Close() error {
b.logger.Debugf("BrowserContext:Close", "bctxid:%v", b.id)
if b.id == "" {
return fmt.Errorf("default browser context can't be closed")
}
if err := b.browser.disposeContext(b.id); err != nil {
return fmt.Errorf("disposing browser context: %w", err)
}
return nil
}
// GrantPermissions enables the specified permissions, all others will be disabled.
func (b *BrowserContext) GrantPermissions(permissions []string, opts GrantPermissionsOptions) error {
b.logger.Debugf("BrowserContext:GrantPermissions", "bctxid:%v", b.id)
permsToProtocol := map[string]cdpbrowser.PermissionType{
"geolocation": cdpbrowser.PermissionTypeGeolocation,
"midi": cdpbrowser.PermissionTypeMidi,
"midi-sysex": cdpbrowser.PermissionTypeMidiSysex,
"notifications": cdpbrowser.PermissionTypeNotifications,
"camera": cdpbrowser.PermissionTypeVideoCapture,
"microphone": cdpbrowser.PermissionTypeAudioCapture,View on GitHub (pinned to 01ffac6f24)