stablyai/orca · error · EmulatorError

emulator_helper_failed

emulator_helper_failed

Error message

serve-sim AX request failed (${response.status}): ${detail}.${retry}

What it means

requestServeSimAccessibilityTree received an HTTP response with a non-2xx status from the serve-sim /ax endpoint. For 503 the message appends a 'warming up, retry' hint because the accessibility service often is not ready immediately after boot.

Source

Thrown at src/main/emulator/serve-sim-accessibility-tree.ts:17

import { net } from 'electron'
import { EmulatorError } from './emulator-errors'
import { normalizeServeSimAxTree, type NormalizedAxNode } from './serve-sim-ax-normalization'

const AX_REQUEST_TIMEOUT_MS = 5_000
const MAX_ERROR_BODY_LENGTH = 512

export async function requestServeSimAccessibilityTree(axUrl: string): Promise<NormalizedAxNode[]> {
  try {
    const response = await net.fetch(axUrl, {
      signal: AbortSignal.timeout(AX_REQUEST_TIMEOUT_MS)
    })
    const body = await response.text()
    if (!response.ok) {
      const detail = body.slice(0, MAX_ERROR_BODY_LENGTH) || response.statusText
      const retry = response.status === 503 ? ' Accessibility may still be warming up; retry.' : ''
      throw new EmulatorError(
        'emulator_helper_failed',
        `serve-sim AX request failed (${response.status}): ${detail}.${retry}`
      )
    }

    let tree: unknown
    try {
      tree = JSON.parse(body)
    } catch {
      throw new EmulatorError('emulator_error', 'serve-sim AX returned invalid JSON.')
    }
    if (
      !Array.isArray(tree) ||
      tree.some((node) => typeof node !== 'object' || node === null || Array.isArray(node))
    ) {
      throw new EmulatorError('emulator_error', 'serve-sim AX returned an invalid tree.')
    }
    // serve-sim reports frames in absolute pixels; normalize to 0..1 so the

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Retry accessibilityTree after a short delay (the 503 case is explicitly retryable).
  2. Ensure `orca emulator attach` completed and the simulator finished booting before the first AX read.
  3. Check serve-sim logs for the status detail embedded in the error message.

Example fix

// before
await requestServeSimAccessibilityTree(axUrl) // 503 right after boot

// after
await waitForSimulatorBooted(udid)
await retry(() => requestServeSimAccessibilityTree(axUrl), { tries: 3, delayMs: 500 })
Defensive patterns

Strategy: retry

Validate before calling

const probe = await fetch(axUrl, { signal: AbortSignal.timeout(1000) }).catch(() => null)
if (probe && probe.status === 503) { /* AX still warming up; wait then call */ }

Type guard

function isEmulatorError(e: unknown, code = 'emulator_helper_failed'): e is import('./emulator-errors').EmulatorError {
  return e instanceof Error && (e as any).code === code && e.name === 'EmulatorError'
}

Try / catch

try { return await requestServeSimAccessibilityTree(axUrl) }
catch (e) {
  if (isEmulatorError(e) && /503|warming up/.test(e.message)) { await delay(500); return await requestServeSimAccessibilityTree(axUrl) }
  throw e
}

Prevention

When it happens

Trigger: net.fetch(axUrl) returns response.ok === false (serve-sim-accessibility-tree.ts:14-20). The first 512 bytes of the body (or statusText) become the detail; status 503 adds the retry suffix.

Common situations: Calling accessibilityTree right after attach (AX not yet warm); serve-sim internal error; simulator still mid-boot; the /ax endpoint temporarily overloaded.

Related errors


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