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

  1. Create your own context with browser.newContext() and use that instead of the default one
  2. Remove the close() call for the default context — k6 closes it automatically when the browser shuts down
  3. 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

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


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)