stablyai/orca · error · EmulatorError

emulator_helper_failed

emulator_helper_failed

Error message

Could not download scrcpy server: ${detail}

What it means

Thrown by downloadScrcpyServerJar when downloadTo(DOWNLOAD_URL, path) rejects. The catch block cleans up the partial file (rmSync), records a probe error, extracts the underlying message, and re-throws as EmulatorError('emulator_helper_failed'). The scrcpy server jar is fetched on demand to mirror the device's scrcpy version.

Source

Thrown at src/main/emulator/android/scrcpy-server-download.ts:57

  }
  if (!inFlightDownload) {
    inFlightDownload = downloadScrcpyServerJar(path).finally(() => {
      inFlightDownload = null
    })
  }
  return inFlightDownload
}

async function downloadScrcpyServerJar(path: string): Promise<string> {
  emulatorProbe('scrcpy.jar.download.start', { url: DOWNLOAD_URL, dest: path })
  mkdirSync(dirname(path), { recursive: true })
  try {
    await downloadTo(DOWNLOAD_URL, path)
  } catch (error) {
    rmSync(path, { force: true })
    emulatorProbeError('scrcpy.jar.download.fail', error, { url: DOWNLOAD_URL })
    const detail = error instanceof Error ? error.message : 'unknown error'
    throw new EmulatorError('emulator_helper_failed', `Could not download scrcpy server: ${detail}`)
  }
  if (!isScrcpyServerJarReady()) {
    rmSync(path, { force: true })
    throw new EmulatorError(
      'emulator_helper_failed',
      'Downloaded scrcpy server was invalid or truncated.'
    )
  }
  emulatorProbe('scrcpy.jar.download.ok', { dest: path, bytes: statSync(path).size })
  return path
}

function downloadTo(url: string, dest: string, redirects = 0): Promise<void> {
  return new Promise((resolve, reject) => {
    if (redirects > 5) {
      reject(new Error('too many redirects'))
      return
    }

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Check connectivity to the scrcpy release URL (curl -I) and allow it through any proxy/firewall.
  2. Pre-download the jar and place it at the expected localJarPath so the runtime fetch is skipped.
  3. Retry — inFlightDownload is cleared on failure so the next session re-attempts.
  4. For proxies, ensure HTTPS_PROXY/HTTP_PROXY env vars are set so downloadTo routes correctly.
  5. Free disk space at the destination if the write stream is failing.

Example fix

// before: relying on runtime fetch behind a firewall
await ScrcpyStreamSession.start({ runner, sdk, serial, localJarPath: cachedOrDownloaded }, cb)
// after: pre-place the jar (or allow the URL)
cp /mnt/cache/scrcpy-server.jar localJarPath
// or: allow the release host through the proxy
export HTTPS_PROXY=http://corp-proxy:3128
Defensive patterns

Strategy: retry

Validate before calling

// Probe reachability before the runtime fetch.
import { request } from 'node:https'
function reachable(url: string): Promise<boolean> {
  return new Promise((res) => {
    const req = request(url, { method: 'HEAD' }, (r) => res(r.statusCode === 200))
    req.on('error', () => res(false))
    req.end()
  })
}

Type guard

import { EmulatorError } from '../emulator-errors'
function isScrcpyDownloadError(e: unknown): e is EmulatorError {
  return e instanceof EmulatorError && e.code === 'emulator_helper_failed' && /download scrcpy/i.test(e.message)
}

Try / catch

for (let attempt = 0; attempt < 3; attempt++) {
  try { return await ScrcpyStreamSession.start(opts, cb) }
  catch (e) {
    if (isScrcpyDownloadError(e) && attempt < 2) { await sleep(1000 * (attempt + 1)); continue }
    throw e
  }
}

Prevention

When it happens

Trigger: First scrcpy session on a host with no cached jar; downloadTo's HTTP request fails (DNS, connection refused, timeout, HTTP >= 400, or >5 redirects). The inFlightDownload de-duplication means only one download is attempted at a time, so concurrent failures share one throw.

Common situations: Offline or firewalled host blocking the scrcpy release URL; corporate proxy intercepting the download; transient network blip; DNS resolution failure; a redirect loop (>5 hops); disk full so the write stream errors mid-download.

Related errors


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