stablyai/orca · error · EmulatorError

emulator_error

emulator_error

Error message

Unknown Android hardware button: ${name}

What it means

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

Source

Thrown at src/main/emulator/android/android-input-mapping.ts:53

  back: 4,
  recents: 187,
  app_switch: 187,
  recent: 187,
  overview: 187,
  power: 26,
  lock: 26,
  volume_up: 24,
  volup: 24,
  volume_down: 25,
  voldown: 25
}

// Accepts the canonical names plus the common aliases above. Throws
// EmulatorError('emulator_error', ...) on an unknown name.
export function androidButtonKeycode(name: string): number {
  const keycode = BUTTON_KEYCODES[name]
  if (keycode === undefined) {
    throw new EmulatorError('emulator_error', `Unknown Android hardware button: ${name}`)
  }
  return keycode
}

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Pass one of the documented names: back, home, recents, menu, lock, volume_up/volup, volume_down/voldown.
  2. Normalize user/external input (lowercase, alias expansion) before calling androidButtonKeycode.
  3. If you need a keycode beyond the map, call adb keyevent directly with the numeric code instead of routing through this helper.

Example fix

// before: unsupported alias
const kc = androidButtonKeycode('recent_apps')
// after: canonical name
const kc = androidButtonKeycode('recents')
Defensive patterns

Strategy: validation

Validate before calling

// Validate against the known map before invoking the helper.
const BUTTON_KEYCODES: Record<string, number> = {
  back: 4, home: 3, recents: 187, menu: 82, lock: 26,
  volume_up: 24, volup: 24, volume_down: 25, voldown: 25
}
function isKnownButton(name: string): boolean {
  return name in BUTTON_KEYCODES
}

Type guard

function isKnownButton(name: string): name is keyof typeof BUTTON_KEYCODES {
  return name in BUTTON_KEYCODES
}

Try / catch

if (!isKnownButton(name)) {
  throw new Error(`Unsupported button '${name}'. Known: ${Object.keys(BUTTON_KEYCODES).join(', ')}`)
}
return androidButtonKeycode(name)

Prevention

When it happens

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

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

Related errors


AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12). Data as JSON: /api/errors/c9c9c69f22d8fa96. Report an issue: GitHub.