stablyai/orca · error · EmulatorError
emulator_error
emulator_error
Error message
Cannot parse empty uiautomator XML
What it means
Thrown by parseUiAutomatorXml when the input string is empty or whitespace-only. It is the first guard before attempting to parse the XML document, distinguishing 'no data' from 'malformed data'. An empty dump usually means `adb shell uiautomator dump` produced no output — the command ran but wrote nothing.
Source
Thrown at src/main/emulator/android/uiautomator-tree.ts:41
export function parseAndroidBounds(value: string): AndroidAxBounds | null {
const match = value.trim().match(/^\[(-?\d+),(-?\d+)\]\[(-?\d+),(-?\d+)\]$/)
if (!match) {
return null
}
return {
left: Number(match[1]),
top: Number(match[2]),
right: Number(match[3]),
bottom: Number(match[4])
}
}
// Parses uiautomator dump XML. The returned node is the synthetic root that
// holds the top-level <node> children of <hierarchy>. Throws
// EmulatorError('emulator_error', ...) on unparseable input.
export function parseUiAutomatorXml(xml: string): AndroidAxNode {
if (xml.trim() === '') {
throw new EmulatorError('emulator_error', 'Cannot parse empty uiautomator XML')
}
let root: RawElement
try {
root = parseDocument(xml)
} catch (error) {
if (error instanceof EmulatorError) {
throw error
}
throw new EmulatorError(
'emulator_error',
`Failed to parse uiautomator XML: ${(error as Error).message}`
)
}
// A bare <node> root is treated as the single top-level node; otherwise take
// the <node> children of <hierarchy>.
const topLevel =
root.tag === 'node' ? [root] : root.children.filter((child) => child.tag === 'node')
return { children: topLevel.map(mapNode) }View on GitHub (pinned to 1136503c6a)
Solutions
- Wait for the device UI to be ready (e.g. sys.boot_completed AND a launcher activity) before dumping.
- Re-run the uiautomator dump and inspect raw stdout length before parsing; retry with backoff if empty.
- Run `adb shell uiautomator dump /sdcard/x.xml && adb shell cat /sdcard/x.xml` manually to see what the device emits.
- If the dump is legitimately empty (no views), handle the empty case upstream rather than feeding it to the parser.
Example fix
// before: parsing whatever dump returns
const tree = parseUiAutomatorXml(dump.stdout)
// after: retry on empty until UI is ready
if (dump.stdout.trim() === '') { await sleep(500); reDump() }
const tree = parseUiAutomatorXml(dump.stdout) Defensive patterns
Strategy: validation
Validate before calling
// Skip parsing when the dump is empty; re-dump instead.
function hasDump(xml: string): boolean { return xml.trim() !== '' } Try / catch
if (!hasDump(xml)) { await sleep(500); xml = await redump() }
if (hasDump(xml)) return parseUiAutomatorXml(xml)
throw new Error('uiautomator dump empty after retry') Prevention
- Wait for sys.boot_completed and a launcher activity before dumping the UI tree.
- Retry the dump with backoff when it returns empty.
- Inspect raw `adb shell uiautomator dump` output when empty dumps persist.
When it happens
Trigger: parseUiAutomatorXml('') or parseUiAutomatorXml(' \n') called with the result of a uiautomator dump that returned an empty string. This precedes the parseDocument call, so it short-circuits before any XML parsing.
Common situations: The uiautomator dump command failed silently (exit 0, empty stdout) on a device where the window manager is not ready; the dump file read failed; the device booted but the UI is not yet rendered; a headless window with no views; an outdated uiautomator binary returning nothing.
Related errors
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/ef57d89dfb8da360.
Report an issue: GitHub.