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
- Check connectivity to the scrcpy release URL (curl -I) and allow it through any proxy/firewall.
- Pre-download the jar and place it at the expected localJarPath so the runtime fetch is skipped.
- Retry — inFlightDownload is cleared on failure so the next session re-attempts.
- For proxies, ensure HTTPS_PROXY/HTTP_PROXY env vars are set so downloadTo routes correctly.
- 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
- Pre-stage the scrcpy server jar at localJarPath to skip the runtime fetch.
- Whitelist the scrcpy release URL through corporate proxies/firewalls.
- Set HTTPS_PROXY/HTTP_PROXY so the fetch routes correctly in restricted networks.
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
- config/scripts/install-electron-package-binary.mjs exited wi
- adb did not return a local scrcpy port
- scrcpy frame size ${size} exceeds ${MAX_FRAME_BYTES}; stream
- Translation request failed with status ${response.status}
- GitHub request failed ${res.status} ${res.statusText}: ${bod
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/292fc17deba8f6f3.
Report an issue: GitHub.