{"record":{"id":"d3bd2bb493a6b820","repo":"microsoft/playwright","slug":"unknown-permission-permission-d3bd2b","errorCode":null,"errorMessage":"Unknown permission: ${permission}","messagePattern":"Unknown permission: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/playwright-core/src/server/webkit/wkPage.ts","lineNumber":1248,"sourceCode":"  }\n\n  _timestampToWallTimeMsForWebSocket(requestId: string, timestamp: number): number {\n    return this._timestampBaselineForWebSocket.get(requestId)! + timestamp * 1000;\n  }\n\n  async _grantPermissions(origin: string, permissions: string[]) {\n    const webPermissionToProtocol = new Map<string, string>([\n      ['geolocation', 'geolocation'],\n      ['notifications', 'notifications'],\n      ['clipboard-read', 'clipboard-read'],\n      ['screen-wake-lock', 'screen-wake-lock'],\n      ['camera', 'camera'],\n      ['microphone', 'microphone'],\n    ]);\n    const filtered = permissions.map(permission => {\n      const protocolPermission = webPermissionToProtocol.get(permission);\n      if (!protocolPermission)\n        throw new Error('Unknown permission: ' + permission);\n      return protocolPermission;\n    });\n    await this._pageProxySession.send('Emulation.grantPermissions', { origin, permissions: filtered });\n  }\n\n  async _clearPermissions() {\n    await this._pageProxySession.send('Emulation.resetPermissions', {});\n  }\n\n  shouldToggleStyleSheetToSyncAnimations(): boolean {\n    return true;\n  }\n\n  async setDockTile(image: Buffer): Promise<void> {\n  }\n}\n\nclass WKFrame {","sourceCodeStart":1230,"sourceCodeEnd":1266,"githubUrl":"https://github.com/microsoft/playwright/blob/c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6/packages/playwright-core/src/server/webkit/wkPage.ts#L1230-L1266","documentation":"_grantPermissions() maps a fixed allowlist of web permissions to WebKit Emulation.grantPermissions codes: geolocation, notifications, clipboard-read, screen-wake-lock, camera, microphone. Any permission not in that map throws 'Unknown permission'. This is the WebKit-specific subset; not every Chromium-supported permission is grantable here.","triggerScenarios":"Calling context.grantPermissions([...]) with a permission string not in the WebKit allowlist (e.g. 'midi', 'persistent-storage', 'idle-detection', 'camera' is fine but 'camera*' variants are not).","commonSituations":"Sharing a permissions list across browsers; Chromium supports more permission strings than WebKit. Copying permission names from MDN/Chrome docs without checking Playwright's WebKit subset. Case/format mistakes.","solutions":["Restrict grantPermissions to the WebKit-allowed set: geolocation, notifications, clipboard-read, screen-wake-lock, camera, microphone.","Branch the permission list per browser when running cross-browser suites.","Filter unknown permissions out before calling, logging the dropped ones."],"exampleFix":"// before\nawait ctx.grantPermissions(['midi', 'geolocation'], { origin });\n\n// after\nawait ctx.grantPermissions(['geolocation'], { origin });","handlingStrategy":"validation","validationCode":"const WK_PERMS = new Set(['geolocation','notifications','clipboard-read','screen-wake-lock','camera','microphone']);\nconst allowed = perms.filter(p => WK_PERMS.has(p));\nawait ctx.grantPermissions(allowed, { origin });","typeGuard":"function isWkPermission(p: string): boolean {\n  return ['geolocation','notifications','clipboard-read','screen-wake-lock','camera','microphone'].includes(p);\n}","tryCatchPattern":"try { await ctx.grantPermissions(perms, { origin }); }\ncatch (e) {\n  if (/Unknown permission/.test(e.message)) await ctx.grantPermissions(perms.filter(isWkPermission), { origin });\n  else throw e;\n}","preventionTips":["Branch permission lists per browser engine.","Filter unknown permissions out and log dropped ones."],"tags":["webkit","permissions","context-options","emulation"],"backgroundTag":null,"analyzedSha":"c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6","analyzedAt":"2026-08-12T07:26:36.950Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}