stablyai/orca · critical · EmulatorError

emulator_error

emulator_error

Error message

Android SDK not found. Install Android Studio and set ANDROID_HOME.

What it means

Thrown by AndroidSdkState.require when resolve() returns null — meaning no SDK paths were injected and discoverAndroidSdkFromHost failed to locate one. The constant message directs the developer to install Android Studio and set ANDROID_HOME. This is a hard prerequisite gate: every Android backend method calls requireSdk() which routes here.

Source

Thrown at src/main/emulator/android/android-sdk-state.ts:24

// Resolves the backend's Android SDK. An injected SDK (tests, or an explicit
// null) is fixed; for the real host it re-runs discovery on every call so a
// newly-installed SDK or a changed configured path takes effect without a
// restart. Host discovery is only a few existsSync probes, so this is cheap.
export class AndroidSdkState {
  constructor(
    private readonly injected: boolean,
    private readonly injectedSdk: AndroidSdkPaths | null
  ) {}

  resolve(): AndroidSdkPaths | null {
    return this.injected ? this.injectedSdk : discoverAndroidSdkFromHost()
  }

  require(): AndroidSdkPaths {
    const sdk = this.resolve()
    if (!sdk) {
      throw new EmulatorError('emulator_error', SDK_MISSING)
    }
    return sdk
  }
}

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Install Android Studio or the command-line tools and set ANDROID_HOME to the SDK root (the folder containing platform-tools/).
  2. Verify the path actually contains platform-tools/adb, emulator/emulator, and build-tools — discoverAndroidSdkFromHost validates structure, not just existence.
  3. In CI/containers, export ANDROID_HOME (and ANDROID_SDK_ROOT for older tools) before launching the app.
  4. If you have a non-standard location, inject it via AndroidSdkState(true, paths) at construction instead of relying on discovery.

Example fix

# before: env unset
export PATH=...
# after: point at a real SDK
export ANDROID_HOME=$HOME/Android/Sdk
export ANDROID_SDK_ROOT=$ANDROID_HOME
# verify structure
ls $ANDROID_HOME/platform-tools/adb $ANDROID_HOME/emulator/emulator
Defensive patterns

Strategy: validation

Validate before calling

// Verify the SDK is discoverable before any Android operation.
function sdkResolved(state: AndroidSdkState): boolean {
  return state.resolve() !== null
}

Type guard

import { existsSync } from 'node:fs'
function sdkLooksComplete(p: { adb: string; emulator: string }): boolean {
  return existsSync(p.adb) && existsSync(p.emulator)
}

Try / catch

try {
  const sdk = sdkState.require()
} catch (e) {
  if (e instanceof EmulatorError && e.code === 'emulator_error' && /Android SDK not found/.test(e.message)) {
    throw new Error('Set ANDROID_HOME to a directory containing platform-tools/ and emulator/')
  }
  throw e
}

Prevention

When it happens

Trigger: AndroidSdkState was constructed with injected=false (or injectedSdk=null) and require() is called. discoverAndroidSdkFromHost checked ANDROID_HOME / ANDROID_SDK_ROOT / common install locations and found nothing usable.

Common situations: Fresh CI worker without Android Studio; ANDROID_HOME set to a path that doesn't contain the expected platform-tools/emulator binaries; SDK installed via command-line tools only but PATH/env not configured; a Docker container missing the env var; the SDK directory exists but platform-tools is absent.

Related errors


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