moeru-ai/airi · error

No ${platform} devices or simulators found. Connect a device

Error message

No ${platform} devices or simulators found. Connect a device, start a simulator or emulator, or pass --target explicitly.

What it means

Thrown by resolveCapRunArgs() when no explicit --target was supplied, no device id is in CAPACITOR_DEVICE_ID_IOS/ANDROID, and listTargets(platform) returned an empty or id-less list. It is the final fallback before cap-vite injects a --target value for the Capacitor run.

Source

Thrown at packages/cap-vite/src/native.ts:155

  let target: string | undefined
  if (platform === 'ios') {
    target = env.CAPACITOR_DEVICE_ID_IOS
  }
  else if (platform === 'android') {
    target = env.CAPACITOR_DEVICE_ID_ANDROID
  }

  if (!target) {
    if (!platform) {
      return capArgs
    }

    const targets = await listTargets(platform)
    target = targets.find(device => device.id)?.id
  }

  if (!target) {
    throw new Error(`No ${platform} devices or simulators found. Connect a device, start a simulator or emulator, or pass --target explicitly.`)
  }

  return [platformArg, '--target', target, ...rest]
}

export function pickServerUrl(server: Pick<ViteDevServer, 'resolvedUrls'>): URL {
  const url = server.resolvedUrls?.network?.[0] ?? server.resolvedUrls?.local?.[0]

  if (!url) {
    throw new Error('Vite did not expose a reachable dev server URL.')
  }

  return new URL(url)
}

export function shouldRestartForNativeChange(file: string, platform: CapacitorPlatform, cwd: string): boolean {
  const absoluteFile = resolve(cwd, file)
  const platformRoot = resolve(cwd, platform)

View on GitHub (pinned to 27111382b4)

Solutions

  1. Start an iOS Simulator (open -a Simulator) or an Android emulator (emulator -avd <name>) and retry.
  2. Connect and trust a physical device over USB/Wi-Fi debugging.
  3. Pass an explicit target: runCapVite(viteArgs, ['ios', '--target', '<id>']).
  4. Set CAPACITOR_DEVICE_ID_IOS or CAPACITOR_DEVICE_ID_ANDROID to a known device id to skip discovery.

Example fix

// before
await runCapVite(viteArgs, ['ios'])
// after
await runCapVite(viteArgs, ['ios', '--target', '00008110-XXXX'])
Defensive patterns

Strategy: try-catch

Validate before calling

// Check device availability before relying on auto-discovery
import { x } from 'tinyexec'

async function hasAnyTarget(platform: 'ios' | 'android'): Promise<boolean> {
  try {
    const out = await x('cap', ['run', platform, '--list', '--json'])
    const list = JSON.parse(out.stdout) as { id?: string }[]
    return list.some(t => typeof t.id === 'string')
  } catch { return false }
}

Try / catch

try {
  await runCapVite(viteArgs, ['ios'])
} catch (error) {
  if (error instanceof Error && /No .* devices or simulators found/.test(error.message)) {
    console.error('Start an iOS Simulator or pass --target <id>.')
    process.exit(1)
  }
  throw error
}

Prevention

When it happens

Trigger: Calling runCapVite or capVitePlugin on a machine with no connected device, no running iOS Simulator, and no running Android emulator; listTargets returns [] because no target has a string id.

Common situations: First run on a fresh dev machine with no simulator booted; CI without a booted emulator; the platform tooling (Xcode simulators / AVD) is installed but nothing is launched; USB device not trusted/paired.

Related errors


AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12). Data as JSON: /api/errors/cc2e9a346c7c9715. Report an issue: GitHub.