microsoft/playwright · error · Error

Unknown permission: ${permission}

Error message

Unknown permission: ${permission}

What it means

_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.

Source

Thrown at packages/playwright-core/src/server/webkit/wkPage.ts:1248

  }

  _timestampToWallTimeMsForWebSocket(requestId: string, timestamp: number): number {
    return this._timestampBaselineForWebSocket.get(requestId)! + timestamp * 1000;
  }

  async _grantPermissions(origin: string, permissions: string[]) {
    const webPermissionToProtocol = new Map<string, string>([
      ['geolocation', 'geolocation'],
      ['notifications', 'notifications'],
      ['clipboard-read', 'clipboard-read'],
      ['screen-wake-lock', 'screen-wake-lock'],
      ['camera', 'camera'],
      ['microphone', 'microphone'],
    ]);
    const filtered = permissions.map(permission => {
      const protocolPermission = webPermissionToProtocol.get(permission);
      if (!protocolPermission)
        throw new Error('Unknown permission: ' + permission);
      return protocolPermission;
    });
    await this._pageProxySession.send('Emulation.grantPermissions', { origin, permissions: filtered });
  }

  async _clearPermissions() {
    await this._pageProxySession.send('Emulation.resetPermissions', {});
  }

  shouldToggleStyleSheetToSyncAnimations(): boolean {
    return true;
  }

  async setDockTile(image: Buffer): Promise<void> {
  }
}

class WKFrame {

View on GitHub (pinned to c8fc3bf8d3)

Solutions

  1. Restrict grantPermissions to the WebKit-allowed set: geolocation, notifications, clipboard-read, screen-wake-lock, camera, microphone.
  2. Branch the permission list per browser when running cross-browser suites.
  3. Filter unknown permissions out before calling, logging the dropped ones.

Example fix

// before
await ctx.grantPermissions(['midi', 'geolocation'], { origin });

// after
await ctx.grantPermissions(['geolocation'], { origin });
Defensive patterns

Strategy: validation

Validate before calling

const WK_PERMS = new Set(['geolocation','notifications','clipboard-read','screen-wake-lock','camera','microphone']);
const allowed = perms.filter(p => WK_PERMS.has(p));
await ctx.grantPermissions(allowed, { origin });

Type guard

function isWkPermission(p: string): boolean {
  return ['geolocation','notifications','clipboard-read','screen-wake-lock','camera','microphone'].includes(p);
}

Try / catch

try { await ctx.grantPermissions(perms, { origin }); }
catch (e) {
  if (/Unknown permission/.test(e.message)) await ctx.grantPermissions(perms.filter(isWkPermission), { origin });
  else throw e;
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of microsoft/playwright@c8fc3bf8d3 (2026-08-12). Data as JSON: /api/errors/d3bd2bb493a6b820. Report an issue: GitHub.