stablyai/orca · error · EmulatorError

emulator_helper_failed

emulator_helper_failed

Error message

serve-sim did not return stream endpoints.

What it means

parseServeSimDetachedSession requires serve-sim's `--detach` output to be a JSON object. A null/non-object payload means the helper invocation produced nothing usable, so no stream endpoints can be derived.

Source

Thrown at src/main/emulator/serve-sim-detached-session.ts:24

const MJPEG_STREAM_SUFFIX = '/stream.mjpeg'

function streamUrlFromServeSimUrl(url: string): string {
  return url.endsWith(MJPEG_STREAM_SUFFIX) ? url : `${url.replace(/\/$/, '')}${MJPEG_STREAM_SUFFIX}`
}

// Derive the helper /ax endpoint by swapping the mjpeg stream suffix. Guarded to
// that suffix so a non-mjpeg stream URL never fabricates a bogus /ax endpoint.
export function deriveAxUrlFromStreamUrl(streamUrl: string | undefined): string | undefined {
  if (!streamUrl || !streamUrl.endsWith(MJPEG_STREAM_SUFFIX)) {
    return undefined
  }
  return `${streamUrl.slice(0, -MJPEG_STREAM_SUFFIX.length)}/ax`
}

export function parseServeSimDetachedSession(raw: unknown, udid: string): EmulatorSessionInfo {
  if (!raw || typeof raw !== 'object') {
    throw new EmulatorError('emulator_helper_failed', 'serve-sim did not return stream endpoints.')
  }
  const json = raw as Record<string, unknown>
  const wsUrl = typeof json.wsUrl === 'string' ? json.wsUrl : undefined
  const streamUrl =
    typeof json.streamUrl === 'string'
      ? json.streamUrl
      : typeof json.url === 'string'
        ? streamUrlFromServeSimUrl(json.url)
        : undefined
  const info: EmulatorSessionInfo = {
    deviceUdid: typeof json.device === 'string' ? json.device : udid,
    wsUrl: wsUrl ?? '',
    streamUrl: streamUrl ?? '',
    axUrl: typeof json.axUrl === 'string' ? json.axUrl : deriveAxUrlFromStreamUrl(streamUrl)
  }
  if (!info.streamUrl || !info.wsUrl) {
    throw new EmulatorError('emulator_helper_failed', 'serve-sim did not return stream endpoints.')
  }

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Verify the serve-sim executable resolves and runs (`serve-sim --version`).
  2. Re-run `orca emulator attach` after restarting the simulator service.
  3. Check serve-sim stderr/logs for the startup error that produced non-JSON stdout.

Example fix

// before
const raw = await execServeSim(['--detach', '-q', udid])
parseServeSimDetachedSession(raw, udid) // raw is a string error

// after
const raw = await execServeSim(['--detach', '-q', udid], { json: true })
if (!raw || typeof raw !== 'object') throw new Error('serve-sim --detach produced no JSON')
parseServeSimDetachedSession(raw, udid)
Defensive patterns

Strategy: validation

Validate before calling

if (!raw || typeof raw !== 'object') { throw new Error('serve-sim --detach produced no JSON object') }

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 parseServeSimDetachedSession(raw, udid) }
catch (e) { if (isEmulatorError(e) && /did not return stream endpoints/.test(e.message)) { /* verify serve-sim binary */ } else throw e }

Prevention

When it happens

Trigger: execServeSim(['--detach','-q',udid]) returns raw that is falsy or typeof !== 'object' (serve-sim-detached-session.ts:23-24).

Common situations: serve-sim binary missing or broken; it printed an error string to stdout instead of JSON; the helper crashed; a version mismatch changed the --detach output shape.

Related errors


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