{"record":{"id":"039857a7e31e2a31","repo":"grafana/k6","slug":"granting-browser-permissions-w","errorCode":null,"errorMessage":"granting browser permissions: %w","messagePattern":"granting browser permissions: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/browser_context.go","lineNumber":250,"sourceCode":"\t\t\"gyroscope\":            cdpbrowser.PermissionTypeSensors,\n\t\t\"magnetometer\":         cdpbrowser.PermissionTypeSensors,\n\t\t\"clipboard-read\":       cdpbrowser.PermissionTypeClipboardReadWrite,\n\t\t\"clipboard-write\":      cdpbrowser.PermissionTypeClipboardSanitizedWrite,\n\t\t\"payment-handler\":      cdpbrowser.PermissionTypePaymentHandler,\n\t}\n\n\tperms := make([]cdpbrowser.PermissionType, 0, len(permissions))\n\tfor _, p := range permissions {\n\t\tproto, ok := permsToProtocol[p]\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"%q is an invalid permission\", p)\n\t\t}\n\t\tperms = append(perms, proto)\n\t}\n\n\taction := cdpbrowser.GrantPermissions(perms).WithOrigin(opts.Origin).WithBrowserContextID(b.id)\n\tif err := action.Do(cdp.WithExecutor(b.ctx, b.browser.conn)); err != nil {\n\t\treturn fmt.Errorf(\"granting browser permissions: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// NewPage creates a new page inside this browser context.\nfunc (b *BrowserContext) NewPage() (*Page, error) {\n\tb.logger.Debugf(\"BrowserContext:NewPage\", \"bctxid:%v\", b.id)\n\t_, span := TraceAPICall(b.ctx, \"\", \"browserContext.newPage\")\n\tdefer span.End()\n\n\tp, err := b.browser.newPageInContext(b.id)\n\tif err != nil {\n\t\treturn nil, spanRecordErrorf(span, \"creating new page in browser context: %w\", err)\n\t}\n\n\tb.logger.Debugf(\"BrowserContext:NewPage:return\", \"bctxid:%v ptid:%s\", b.id, p.targetID)\n\treturn p, nil","sourceCodeStart":232,"sourceCodeEnd":268,"githubUrl":"https://github.com/grafana/k6/blob/01ffac6f245854c1b8adc6a69857c76a15f90022/internal/js/modules/k6/browser/common/browser_context.go#L232-L268","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pass origin with an explicit scheme: { origin: 'https://example.com' }, or omit it to grant for all origins","Grant permissions right after creating the context, before any page work and before close","Read the wrapped CDP message — it distinguishes bad origin from closed context","If policy blocks the permission (camera/mic on locked-down images), remove it from the list or use an image that allows it"],"exampleFix":"// before\nctx.grantPermissions(['geolocation'], { origin: 'example.com' }); // malformed origin\n\n// after\nctx.grantPermissions(['geolocation'], { origin: 'https://example.com' });","handlingStrategy":"validation","validationCode":"// origins must include a scheme; validate before granting\nfunction isValidOrigin(o) {\n  return o === undefined || /^https?:\\/\\/[\\w.-]+(:\\d+)?$/.test(o);\n}\nconst origin = 'https://example.com';\nif (isValidOrigin(origin)) {\n  ctx.grantPermissions(['geolocation'], { origin });\n}","typeGuard":null,"tryCatchPattern":"try {\n  ctx.grantPermissions(perms, { origin });\n} catch (e) {\n  if (String(e.message).includes('granting browser permissions')) {\n    // inspect e for the CDP reason: bad origin vs closed context vs dead browser\n    throw new Error(`grant failed: ${e.message}`);\n  }\n  throw e;\n}","preventionTips":["Always pass origin as 'https://host' including the scheme","Grant permissions right after newContext, before pages and before any close","On locked-down CI images, avoid camera/microphone grants"],"tags":["browser","cdp","permissions","origin"],"backgroundTag":"cdp-protocol-error","analyzedSha":"01ffac6f245854c1b8adc6a69857c76a15f90022","analyzedAt":"2026-08-18T03:05:52.393Z","contentChangedAt":"2026-08-18T03:05:52.393Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}