grafana/k6 · error

granting browser permissions

Error message

granting browser permissions: %w

What it means

The permission names were valid, but the CDP command Browser.grantPermissions failed for this context/origin. The wrapped error carries Chromium's reason: malformed origin, unknown browser context ID, or a transport failure. Nothing is partially granted — the command is atomic per call.

Solutions

  1. Pass origin with an explicit scheme: { origin: 'https://example.com' }, or omit it to grant for all origins
  2. Grant permissions right after creating the context, before any page work and before close
  3. Read the wrapped CDP message — it distinguishes bad origin from closed context
  4. If policy blocks the permission (camera/mic on locked-down images), remove it from the list or use an image that allows it

Example fix

// before
ctx.grantPermissions(['geolocation'], { origin: 'example.com' }); // malformed origin

// after
ctx.grantPermissions(['geolocation'], { origin: 'https://example.com' });
Defensive patterns

Strategy: validation

Validate before calling

// origins must include a scheme; validate before granting
function isValidOrigin(o) {
  return o === undefined || /^https?:\/\/[\w.-]+(:\d+)?$/.test(o);
}
const origin = 'https://example.com';
if (isValidOrigin(origin)) {
  ctx.grantPermissions(['geolocation'], { origin });
}

Try / catch

try {
  ctx.grantPermissions(perms, { origin });
} catch (e) {
  if (String(e.message).includes('granting browser permissions')) {
    // inspect e for the CDP reason: bad origin vs closed context vs dead browser
    throw new Error(`grant failed: ${e.message}`);
  }
  throw e;
}

Prevention

When it happens

Trigger: grantPermissions(perms, { origin: 'example.com' }) without a scheme; granting on a context that was already closed; granting while the browser connection is down; headless shells or enterprise policies refusing camera/microphone grants.

Common situations: Origin passed as bare hostname instead of 'https://example.com'; permissions code running in teardown after context disposal; CI environments where policy blocks sensitive permissions.

Related errors


AI-assisted analysis of grafana/k6@01ffac6f24 (2026-08-18). Data as JSON: /api/errors/039857a7e31e2a31. Report an issue: GitHub.

Appendix: source

Thrown at internal/js/modules/k6/browser/common/browser_context.go:250

		"gyroscope":            cdpbrowser.PermissionTypeSensors,
		"magnetometer":         cdpbrowser.PermissionTypeSensors,
		"clipboard-read":       cdpbrowser.PermissionTypeClipboardReadWrite,
		"clipboard-write":      cdpbrowser.PermissionTypeClipboardSanitizedWrite,
		"payment-handler":      cdpbrowser.PermissionTypePaymentHandler,
	}

	perms := make([]cdpbrowser.PermissionType, 0, len(permissions))
	for _, p := range permissions {
		proto, ok := permsToProtocol[p]
		if !ok {
			return fmt.Errorf("%q is an invalid permission", p)
		}
		perms = append(perms, proto)
	}

	action := cdpbrowser.GrantPermissions(perms).WithOrigin(opts.Origin).WithBrowserContextID(b.id)
	if err := action.Do(cdp.WithExecutor(b.ctx, b.browser.conn)); err != nil {
		return fmt.Errorf("granting browser permissions: %w", err)
	}

	return nil
}

// NewPage creates a new page inside this browser context.
func (b *BrowserContext) NewPage() (*Page, error) {
	b.logger.Debugf("BrowserContext:NewPage", "bctxid:%v", b.id)
	_, span := TraceAPICall(b.ctx, "", "browserContext.newPage")
	defer span.End()

	p, err := b.browser.newPageInContext(b.id)
	if err != nil {
		return nil, spanRecordErrorf(span, "creating new page in browser context: %w", err)
	}

	b.logger.Debugf("BrowserContext:NewPage:return", "bctxid:%v ptid:%s", b.id, p.targetID)
	return p, nil

View on GitHub (pinned to 01ffac6f24)