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
- 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.
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
- 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.
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
- coordinate action requires a visible window and coordinates
- {name} must be a positive integer
- Hermes cron requires a prompt.
- Hermes cron requires a schedule.
- A Claude config directory path is required.
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/c9c9c69f22d8fa96.
Report an issue: GitHub.