{"record":{"id":"0422a3608bd3d606","repo":"grafana/k6","slug":"q-is-an-invalid-permission","errorCode":null,"errorMessage":"%q is an invalid permission","messagePattern":"%q is an invalid permission","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/js/modules/k6/browser/common/browser_context.go","lineNumber":243,"sourceCode":"\t\t\"midi-sysex\":           cdpbrowser.PermissionTypeMidiSysex,\n\t\t\"notifications\":        cdpbrowser.PermissionTypeNotifications,\n\t\t\"camera\":               cdpbrowser.PermissionTypeVideoCapture,\n\t\t\"microphone\":           cdpbrowser.PermissionTypeAudioCapture,\n\t\t\"background-sync\":      cdpbrowser.PermissionTypeBackgroundSync,\n\t\t\"ambient-light-sensor\": cdpbrowser.PermissionTypeSensors,\n\t\t\"accelerometer\":        cdpbrowser.PermissionTypeSensors,\n\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","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/grafana/k6/blob/01ffac6f245854c1b8adc6a69857c76a15f90022/internal/js/modules/k6/browser/common/browser_context.go#L225-L261","documentation":"GrantPermissions maps friendly permission strings to CDP PermissionType values before issuing Browser.grantPermissions; the given string is not in the allowlist. Names accepted by this build: geolocation, midi, midi-sysex, notifications, camera, microphone, background-sync, ambient-light-sensor, accelerometer, gyroscope, magnetometer, clipboard-read, clipboard-write, payment-handler. The check is client-side, so nothing reaches the browser.","triggerScenarios":"browserContext.grantPermissions(['notification']) (singular), Chromium raw names like 'clipboardReadWrite' or 'sensors', empty strings, or a comma-joined string 'geolocation,camera' instead of an array element.","commonSituations":"Typos and singular/plural mistakes; copying permission names from Chromium flag strings or other tools' docs instead of the k6/Playwright list; building the array dynamically from unvalidated config.","solutions":["Use the exact names from the allowlist above, e.g. grantPermissions(['notifications', 'geolocation'])","Validate your permission array against the allowlist before calling the API","Check for accidental concatenation — pass an array of separate strings"],"exampleFix":"// before\nctx.grantPermissions(['notification', 'clipboardReadWrite']); // both invalid\n\n// after\nctx.grantPermissions(['notifications', 'clipboard-read', 'clipboard-write']);","handlingStrategy":"validation","validationCode":"const VALID_PERMISSIONS = new Set([\n  'geolocation', 'midi', 'midi-sysex', 'notifications',\n  'camera', 'microphone', 'background-sync', 'ambient-light-sensor',\n  'accelerometer', 'gyroscope', 'magnetometer',\n  'clipboard-read', 'clipboard-write', 'payment-handler',\n]);\nfunction assertValidPermissions(perms) {\n  for (const p of perms) {\n    if (!VALID_PERMISSIONS.has(p)) {\n      throw new Error(`invalid permission '${p}'; allowed: ${[...VALID_PERMISSIONS].join(', ')}`);\n    }\n  }\n}\nassertValidPermissions(['notifications', 'geolocation']);\nctx.grantPermissions(['notifications', 'geolocation']);","typeGuard":"const isPermissionName = (p) => typeof p === 'string' && VALID_PERMISSIONS.has(p);","tryCatchPattern":null,"preventionTips":["Copy permission names from the k6 browser docs allowlist, not Chromium flag strings","Validate dynamic permission arrays against a Set before granting","Watch for singular forms ('notification') — they are the most common typo"],"tags":["browser","permissions","validation","enum"],"backgroundTag":"invalid-enum-value","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"}