expo/expo · error · CommandError
Unable to launch app, number of tries exceeded
Error message
Unable to launch app, number of tries exceeded
What it means
The companion error to 153: the launch retry loop tolerates 'EBusy'/'ENotFound' for up to 3 attempts with a 500ms backoff (delayAsync). If all three attempts still return a busy/not-found status, the loop exits and throws this CommandError. It means the device/debugserver was persistently unavailable during the launch window.
Source
Thrown at packages/@expo/cli/src/run/ios/appleDevice/AppleDevice.ts:296
debugEvent('apple_device:disconnect_response', { result: res });
if (res !== 'OK') {
console.warn(
'Something went wrong while attempting to disconnect from iOS debug server, you may need to reopen the app manually.'
);
}
}
return debugServerClient;
} else if (result === 'EBusy' || result === 'ENotFound') {
debugEvent('apple_device:launch_retry', { tries });
tries++;
debugServerClient.socket.end();
await delayAsync(500);
} else {
throw new CommandError(`There was an error launching app: ${result}`);
}
}
throw new CommandError('Unable to launch app, number of tries exceeded');
}
/**
* iOS 17 introduces a new protocol called RemoteXPC.
* This is not yet implemented, so we fallback to devicectl.
*
* @see https://github.com/doronz88/pymobiledevice3/blob/master/misc/RemoteXPC.md#process-remoted
*/
async function launchApp(
clientManager: ClientManager,
{
bundleId,
appInfo,
detach,
}: { bundleId: string; appInfo: IPLookupResult[string]; detach?: boolean }
) {
try {
return await launchAppWithUsbmux(clientManager, { appInfo, detach });View on GitHub (pinned to b09195aac2)
Solutions
- Wait a few seconds and re-run; the device usually frees up.
- Close other tools that talk to the device over USB (Xcode, Finder sync, iMazing).
- Unplug/replug the device or restart it to reset the debugserver state.
- If it persists on iOS 17+, the RemoteXPC/devicectl fallback path may be needed — update @expo/cli to a version with iOS 17 support.
Defensive patterns
Strategy: retry
Try / catch
for (let attempt = 0; attempt < 3; attempt++) {
try {
return await launchOnDevice(...);
} catch (e) {
if (e instanceof CommandError && /number of tries exceeded/.test(e.message) && attempt < 2) {
await delay(2000); // longer than the inner 500ms backoff
continue;
}
throw e;
}
} Prevention
- Avoid back-to-back run:ios on the same device without pausing.
- Close Xcode/other USB holders before physical-device runs.
- On persistent EBusy, replug or restart the device.
When it happens
Trigger: Three consecutive checkLaunchSuccess() calls returning 'EBusy' or 'ENotFound' within ~1.5s: a device that is still processing a previous install/launch, SpringBoard busy, a long app-attach/signing operation in progress, or a debugserver that is overloaded.
Common situations: Rapidly re-running run:ios without letting the previous install finish; a low-powered device (older iPhones) where 500ms×3 is not enough; USB throughput contention with other tools (Xcode, iMazing) holding the device; iOS beta instability.
Related errors
- There was an error launching app: ${result}
- APPLE_DEVICE_AFC
- There was an error looking up app
- Error starting service ${name}
- Error starting session
AI-assisted analysis of expo/expo@b09195aac2 (2026-08-12).
Data as JSON: /api/errors/e4fd292a18649c95.
Report an issue: GitHub.