{"record":{"id":"430dbc8c5dd23d27","repo":"stablyai/orca","slug":"emulator-error","errorCode":"emulator_error","errorMessage":"${label} failed: ${(result.stderr || result.stdout).trim() || 'unknown error'}","messagePattern":"(.+?) failed: (.+?)","errorType":"exception","errorClass":"EmulatorError","httpStatus":null,"severity":"error","filePath":"src/main/emulator/android/android-adb-result.ts","lineNumber":8,"sourceCode":"import { EmulatorError } from '../emulator-errors'\nimport type { AndroidCommandResult } from './android-command-runner'\n\n// AndroidCommandRunner resolves non-zero exits as data; callers must opt into\n// throwing so adb failures do not become silent successful emulator actions.\nexport function ensureAdbOk(result: AndroidCommandResult, label: string): AndroidCommandResult {\n  if (result.code !== 0) {\n    throw new EmulatorError(\n      'emulator_error',\n      `${label} failed: ${(result.stderr || result.stdout).trim() || 'unknown error'}`\n    )\n  }\n  return result\n}\n","sourceCodeStart":1,"sourceCodeEnd":15,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/emulator/android/android-adb-result.ts#L1-L15","documentation":"ensureAdbOk throws EmulatorError('emulator_error') when an AndroidCommandResult reports a non-zero exit code. The Android command runner deliberately resolves adb failures as data (code !== 0) rather than rejecting, so silent successes are impossible; callers opt into throwing by piping the result through ensureAdbOk with a human-readable label. The message embeds the trimmed stderr (falling back to stdout, then 'unknown error') for diagnosis.","triggerScenarios":"Calling ensureAdbOk(result, label) after any adb invocation routed through AndroidCommandRunner — e.g. scrcpy server push, scrcpy port forward, device probes — where result.code !== 0. Anywhere the runner is used and the caller needs a hard failure (contrast: boot polling where non-zero is an expected 'not booted yet' signal).","commonSituations":"Device disconnected between a serial resolution and the adb call (USB unplugged, emulator killed); insufficient adb permissions on Linux (missing udev rules) producing exit 1; an unauthorized device (adb in 'offline'/'unauthorized' state); a malformed serial or a stale adb server needing `adb killserver`; scrcpy server push failing because /sdcard is full or read-only.","solutions":["Inspect the embedded stderr in the message — adb usually states the precise failure (device offline, unauthorized, more than one device).","Verify the device is still present: `adb devices` and confirm the serial is 'device' (not 'offline'/'unauthorized').","Restart the adb server (`adb kill-server && adb start-server`) when state is stale.","On Linux permission errors, install the platform udev rules and ensure the user is in the plugdev/adb group.","Re-run with the runner's logging enabled to capture the exact argv and full stderr if the trimmed message is incomplete."],"exampleFix":"// before: treating adb result as always-OK\nconst r = await runner(sdk.adb, pushArgs(serial, jar))\nuse(r.stdout)\n// after: opt into a hard failure with a label\nimport { ensureAdbOk } from '../android-adb-result'\nconst r = ensureAdbOk(await runner(sdk.adb, pushArgs(serial, jar)), 'scrcpy server push')\nuse(r.stdout)","handlingStrategy":"try-catch","validationCode":"// Inspect the result before opting in; lets callers branch instead of throw.\nimport type { AndroidCommandResult } from './android-command-runner'\nfunction adbOk(r: AndroidCommandResult): boolean {\n  return r.code === 0\n}","typeGuard":"import { EmulatorError } from '../emulator-errors'\nfunction isEmulatorError(e: unknown): e is EmulatorError {\n  return e instanceof EmulatorError\n}","tryCatchPattern":"try {\n  ensureAdbOk(await runner(sdk.adb, args), 'push')\n} catch (e) {\n  if (e instanceof EmulatorError && e.code === 'emulator_error') {\n    // device may have disconnected — re-probe before retrying\n    await refreshDeviceList()\n  }\n  throw e\n}","preventionTips":["Validate the device serial is 'device' status in adb devices before issuing commands.","Restart the adb server (`adb kill-server && adb start-server`) when stale state is suspected.","On Linux, install platform udev rules so adb exits cleanly."],"tags":["android","adb","emulator","device-disconnected"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}