grafana/k6 · error

default browser context can't be closed

Error message

default browser context can't be closed

What it means

browser.context() returns chromium's implicit default browser context, whose internal ID is the empty string. BrowserContext.Close (browser_context.go:210) explicitly refuses to close it: 'default browser context can't be closed'. The default context is owned by the browser process and is torn down when the browser closes, so k6 rejects the call outright.

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 93accf6570)

Solutions

  1. Only close contexts you created with browser.newContext()
  2. Guard the close: skip it when the context is browser.context()
  3. Rely on browser.close() to tear down the default context and its pages

Example fix

// before
const ctx = browser.context()
await ctx.close() // throws: default browser context can't be closed

// after
const ctx = browser.newContext()
await ctx.close() // OK
// or: let browser.close() clean up the default context
Defensive patterns

Strategy: type-guard

Validate before calling

const isDefault = (ctx) => ctx === browser.context()
if (!isDefault(ctx)) await ctx.close()

Type guard

function isDefaultContext(ctx, browser) {
  return ctx === browser.context()
}

Try / catch

try {
  await ctx.close()
} catch (e) {
  if (/default browser context can't be closed/.test(String(e))) {
    // expected when handed the default context — ignore
  } else throw e
}

Prevention

When it happens

Trigger: const ctx = browser.context(); await ctx.close(); — the only way to hit it. Also generic helpers that blindly close every context they are handed, including the default one.

Common situations: Code ported from Playwright, where closing the default context is permitted; scripts that iterate all contexts and close them; shared teardown closing browser.context() alongside user contexts.

Related errors


AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15). Data as JSON: /api/errors/4e49dd7feaffdfae. Report an issue: GitHub.