microsoft/playwright · error · Error

Unknown modifier ${modifier}

Error message

Unknown modifier ${modifier}

What it means

Thrown by Keyboard.ensureModifiers() when a resolved modifier is not in the kModifiers set ['Alt', 'Control', 'Meta', 'Shift']. The method maps each input through resolveSmartModifier (which handles ControlOrMeta) and then validates against the four allowed modifier keys. Any modifier outside this set is rejected.

Source

Thrown at packages/playwright-core/src/server/input.ts:161

    }

    const tokens = split(key);
    key = tokens[tokens.length - 1];
    for (let i = 0; i < tokens.length - 1; ++i)
      await this.down(progress, tokens[i]);
    await this.down(progress, key);
    if (options.delay)
      await progress.wait(options.delay);
    await this.up(progress, key);
    for (let i = tokens.length - 2; i >= 0; --i)
      await this.up(progress, tokens[i]);
  }

  async ensureModifiers(progress: Progress, mm: types.SmartKeyboardModifier[]): Promise<types.KeyboardModifier[]> {
    const modifiers = mm.map(resolveSmartModifier);
    for (const modifier of modifiers) {
      if (!kModifiers.includes(modifier))
        throw new Error('Unknown modifier ' + modifier);
    }
    const restore: types.KeyboardModifier[] = Array.from(this._pressedModifiers);
    for (const key of kModifiers) {
      const needDown = modifiers.includes(key);
      const isDown = this._pressedModifiers.has(key);
      if (needDown && !isDown)
        await this.down(progress, key);
      else if (!needDown && isDown)
        await this.up(progress, key);
    }
    return restore;
  }

  _modifiers(): Set<types.KeyboardModifier> {
    return this._pressedModifiers;
  }
}

View on GitHub (pinned to c8fc3bf8d3)

Solutions

  1. Use only the four canonical modifier names: 'Alt', 'Control', 'Meta', 'Shift'.
  2. Use 'ControlOrMeta' for cross-platform modifier (resolves to Meta on macOS, Control on other platforms).
  3. Map platform-specific names before passing: { Cmd: 'Meta', Option: 'Alt', Ctrl: 'Control' }.

Example fix

// before
await keyboard.ensureModifiers(['Cmd', 'Shift']);

// after
await keyboard.ensureModifiers(['Meta', 'Shift']);
Defensive patterns

Strategy: validation

Validate before calling

const VALID_MODIFIERS = new Set(['Alt','Control','Meta','Shift','ControlOrMeta']);
function validateModifiers(modifiers) {
  for (const m of modifiers)
    if (!VALID_MODIFIERS.has(m))
      throw new Error(`Unknown modifier: ${m}`);
}

Type guard

function isModifier(key: string): key is 'Alt' | 'Control' | 'Meta' | 'Shift' | 'ControlOrMeta' {
  return ['Alt','Control','Meta','Shift','ControlOrMeta'].includes(key);
}

Prevention

When it happens

Trigger: Calling internal keyboard APIs that use ensureModifiers with an invalid modifier name. In normal usage this is rare since the public API only accepts valid modifiers, but custom selector engines or internal tool integrations may pass unexpected values.

Common situations: Passing 'Cmd' (should be 'Meta'), 'Option' (should be 'Alt'), 'Ctrl' (should be 'Control'), or 'Win' (should be 'Meta'). Custom automation code that constructs modifier arrays dynamically. Integration with third-party tools that use platform-specific modifier names.

Related errors


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