{"record":{"id":"c9c9c69f22d8fa96","repo":"stablyai/orca","slug":"emulator-error-c9c9c6","errorCode":"emulator_error","errorMessage":"Unknown Android hardware button: ${name}","messagePattern":"Unknown Android hardware button: (.+?)","errorType":"exception","errorClass":"EmulatorError","httpStatus":null,"severity":"error","filePath":"src/main/emulator/android/android-input-mapping.ts","lineNumber":53,"sourceCode":"  back: 4,\n  recents: 187,\n  app_switch: 187,\n  recent: 187,\n  overview: 187,\n  power: 26,\n  lock: 26,\n  volume_up: 24,\n  volup: 24,\n  volume_down: 25,\n  voldown: 25\n}\n\n// Accepts the canonical names plus the common aliases above. Throws\n// EmulatorError('emulator_error', ...) on an unknown name.\nexport function androidButtonKeycode(name: string): number {\n  const keycode = BUTTON_KEYCODES[name]\n  if (keycode === undefined) {\n    throw new EmulatorError('emulator_error', `Unknown Android hardware button: ${name}`)\n  }\n  return keycode\n}\n","sourceCodeStart":35,"sourceCodeEnd":57,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/emulator/android/android-input-mapping.ts#L35-L57","documentation":"Thrown by androidButtonKeycode when the supplied name has no entry in the BUTTON_KEYCODES map. The map accepts canonical names (back, home, recents, menu, lock, volume_up/down) plus aliases (volup, voldown). The function is the single source of truth that translates a hardware-button name to the Android KeyEvent keycode used by `adb shell input keyevent`.","triggerScenarios":"androidButtonKeycode(name) called with a string not present as a key in BUTTON_KEYCODES — e.g. a platform-specific button name ('recent_apps' instead of 'recents'), a vendor key, an empty string, or a casing mismatch (the lookup is case-sensitive).","commonSituations":"An agent or test harness passing a button name sourced from an external API that uses different naming than this map; UI layer not normalizing user input before calling the backend; a typo ('volum_up'); passing an iOS-specific button name into the Android backend.","solutions":["Pass one of the documented names: back, home, recents, menu, lock, volume_up/volup, volume_down/voldown.","Normalize user/external input (lowercase, alias expansion) before calling androidButtonKeycode.","If you need a keycode beyond the map, call adb keyevent directly with the numeric code instead of routing through this helper."],"exampleFix":"// before: unsupported alias\nconst kc = androidButtonKeycode('recent_apps')\n// after: canonical name\nconst kc = androidButtonKeycode('recents')","handlingStrategy":"validation","validationCode":"// Validate against the known map before invoking the helper.\nconst BUTTON_KEYCODES: Record<string, number> = {\n  back: 4, home: 3, recents: 187, menu: 82, lock: 26,\n  volume_up: 24, volup: 24, volume_down: 25, voldown: 25\n}\nfunction isKnownButton(name: string): boolean {\n  return name in BUTTON_KEYCODES\n}","typeGuard":"function isKnownButton(name: string): name is keyof typeof BUTTON_KEYCODES {\n  return name in BUTTON_KEYCODES\n}","tryCatchPattern":"if (!isKnownButton(name)) {\n  throw new Error(`Unsupported button '${name}'. Known: ${Object.keys(BUTTON_KEYCODES).join(', ')}`)\n}\nreturn androidButtonKeycode(name)","preventionTips":["Normalize external button names (lowercase, alias map) before calling androidButtonKeycode.","Keep a documented allow-list in the UI layer so users pick valid names.","For non-mapped keys, call adb keyevent with the numeric code directly."],"tags":["android","input","keycode","validation"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}