{"record":{"id":"342906b146ca82a9","repo":"microsoft/playwright","slug":"unknown-key-params-key","errorCode":null,"errorMessage":"Unknown key: ${params.key}","messagePattern":"Unknown key: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/playwright-core/src/server/dispatchers/androidDispatcher.ts","lineNumber":127,"sourceCode":"    fixupAndroidElementInfo(info);\n    return { info };\n  }\n\n  async inputType(params: channels.AndroidDeviceInputTypeParams, progress: Progress) {\n    const text = params.text;\n    const keyCodes: number[] = [];\n    for (let i = 0; i < text.length; ++i) {\n      const code = keyMap.get(text[i].toUpperCase());\n      if (code === undefined)\n        throw new Error('No mapping for ' + text[i] + ' found');\n      keyCodes.push(code);\n    }\n    await progress.race(Promise.all(keyCodes.map(keyCode => this._object.send(progress, 'inputPress', { keyCode }))));\n  }\n\n  async inputPress(params: channels.AndroidDeviceInputPressParams, progress: Progress) {\n    if (!keyMap.has(params.key))\n      throw new Error('Unknown key: ' + params.key);\n    await this._object.send(progress, 'inputPress', { keyCode: keyMap.get(params.key) });\n  }\n\n  async inputTap(params: channels.AndroidDeviceInputTapParams, progress: Progress) {\n    await this._object.send(progress, 'inputClick', params);\n  }\n\n  async inputSwipe(params: channels.AndroidDeviceInputSwipeParams, progress: Progress) {\n    await this._object.send(progress, 'inputSwipe', params);\n  }\n\n  async inputDrag(params: channels.AndroidDeviceInputDragParams, progress: Progress) {\n    await this._object.send(progress, 'inputDrag', params);\n  }\n\n  async screenshot(params: channels.AndroidDeviceScreenshotParams, progress: Progress): Promise<channels.AndroidDeviceScreenshotResult> {\n    return { binary: await this._object.screenshot(progress) };\n  }","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/microsoft/playwright/blob/c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6/packages/playwright-core/src/server/dispatchers/androidDispatcher.ts#L109-L145","documentation":"Thrown by AndroidDeviceDispatcher.inputPress() when params.key is not a key in keyMap. Unlike inputType, inputPress checks keyMap.has(params.key) directly with NO toUpperCase(), so the lookup is case-sensitive: lowercase 'a' fails even though 'A' is mapped. Only the exact spellings in keyMap (capital letters A-Z, digits as strings, and named keys like 'Enter', 'Back', 'Home', 'VolumeUp', 'MediaPlayPause') are accepted.","triggerScenarios":"Calling androidDevice.press(key) with a lowercase letter ('a'), an unmapped name ('Escape', 'Control', 'Alt', 'ArrowDown', 'F1'), a typo'd name ('Return' instead of 'Enter', 'HomeButton' instead of 'Home'), or any key not listed in the Android keyMap.","commonSituations":"Reusing keyboard key constants from the Page API (which accepts 'Escape', 'Control', arrows, lowercase) on Android; copy-pasting desktop key names into Android tests; assuming the Android key set matches USB HID / Playwright keyboard key codes.","solutions":["Use the exact Android key names from keyMap: single capital letters for letters ('A' not 'a'), string digits ('0'..'9'), and the named Android keys ('Enter', 'Back', 'Home', 'VolumeUp', 'MediaPlayPause', etc.).","Uppercase single letters before pressing: press(ch.toUpperCase()).","Replace desktop-only keys with the closest Android equivalent (e.g. 'Escape' -> 'Back', 'ArrowLeft/Right' -> 'DialLeft'/'DialRight' where appropriate) or omit them."],"exampleFix":"// before: desktop key names / lowercase fail\nawait device.press('escape');\nawait device.press('a');\n\n// after: exact Android keyMap names\nawait device.press('Back');\nawait device.press('A');\nawait device.press('Enter');","handlingStrategy":"validation","validationCode":"const ANDROID_KEYS = new Set(['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','0','1','2','3','4','5','6','7','8','9','Enter','Back','Home','VolumeUp','VolumeDown','Power','Camera','Clear','Tab','Space','Search','Menu']); // extend from keyMap\nfunction isAndroidKey(key: string): boolean {\n  return ANDROID_KEYS.has(key);\n}\nif (!isAndroidKey(key)) throw new Error(`Unsupported Android key: ${key}`);","typeGuard":"function isAndroidKeyName(key: string): key is string {\n  // Exact names from androidDispatcher keyMap; case-sensitive.\n  return ANDROID_KEYS.has(key);\n}","tryCatchPattern":null,"preventionTips":["Use a constant set built from the keyMap in androidDispatcher.ts as the single source of truth for valid keys.","Uppercase single letters before press(): key = ch.toUpperCase().","Do not reuse desktop/Page-API key names ('Escape','ArrowDown','Control') for Android; map them explicitly to Android names."],"tags":["android","input","key","keymap","validation"],"backgroundTag":null,"analyzedSha":"c8fc3bf8d31542d59b4d4d9eaab1df93ff541dc6","analyzedAt":"2026-08-12T07:26:36.950Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}