moeru-ai/airi · error
The first `cap run` argument must be `ios` or `android`.
Error message
The first `cap run` argument must be `ios` or `android`.
What it means
Thrown by runCapVite() when capArgs[0] is not parseable by parseCapacitorPlatform(), which only accepts the literal strings 'ios' or 'android'. This is the CLI entry point of @proj-airi/cap-vite and is the first guard before forwarding args into Vite and the Capacitor run subprocess.
Source
Thrown at packages/cap-vite/src/index.ts:157
index += parsedArg.consumedArgs
}
return {
baseConfigFile,
configLoader,
projectRoot,
viteArgs: forwardedViteArgs,
wrapperConfigFile: resolveWrapperConfigFile(),
}
}
export async function runCapVite(
viteArgs: string[],
capArgs: string[],
options: RunCapViteOptions = {},
): Promise<Output> {
if (!parseCapacitorPlatform(capArgs[0])) {
throw new Error('The first `cap run` argument must be `ios` or `android`.')
}
const cwd = resolve(options.cwd ?? process.cwd())
const prepared = prepareCapViteLaunch(viteArgs, cwd)
return await x('vite', ['--config', prepared.wrapperConfigFile, ...prepared.viteArgs], {
throwOnError: false,
nodeOptions: {
cwd,
env: {
CAP_VITE_BASE_CONFIG: prepared.baseConfigFile ?? '',
CAP_VITE_CAP_ARGS_JSON: JSON.stringify(capArgs),
CAP_VITE_CONFIG_LOADER: prepared.configLoader ?? '',
CAP_VITE_ROOT: prepared.projectRoot,
},
stdio: 'inherit',
},
})View on GitHub (pinned to 27111382b4)
Solutions
- Ensure the first element of the capArgs array is exactly 'ios' or 'android' (lowercase).
- If the platform comes from user input, normalize and validate it before calling runCapVite using parseCapacitorPlatform().
- Reorder args so the platform precedes any --target flag: runCapVite(viteArgs, ['ios', '--target', deviceId]).
Example fix
// before await runCapVite(viteArgs, ['--target', deviceId]) // after await runCapVite(viteArgs, ['ios', '--target', deviceId])
Defensive patterns
Strategy: validation
Validate before calling
import { parseCapacitorPlatform } from '@proj-airi/cap-vite'
function assertCapPlatform(capArgs: string[]): asserts capArgs is ['ios' | 'android', ...string[]] {
if (!parseCapacitorPlatform(capArgs[0])) {
throw new TypeError(`capArgs[0] must be 'ios' or 'android', got: ${String(capArgs[0])}`)
}
}
assertCapPlatform(capArgs)
await runCapVite(viteArgs, capArgs) Type guard
import { parseCapacitorPlatform } from '@proj-airi/cap-vite'
function isCapArgs(value: unknown): value is ['ios' | 'android', ...string[]] {
return Array.isArray(value)
&& (value[0] === 'ios' || value[0] === 'android')
&& value.every(v => typeof v === 'string')
} Try / catch
try {
await runCapVite(viteArgs, capArgs)
} catch (error) {
if (error instanceof Error && error.message.includes('must be `ios` or `android`')) {
console.error('Usage: cap-vite <ios|android> [vite args]')
process.exit(2)
}
throw error
} Prevention
- Always place the platform token as the first element of capArgs.
- Validate platform at your CLI boundary before forwarding to runCapVite.
- Normalize user input to lowercase before comparing.
When it happens
Trigger: Calling runCapVite(viteArgs, capArgs) with capArgs[0] missing, undefined, empty string, or any value other than 'ios'/'android' (e.g. 'web', 'electron', '--target'). Also triggered by argument-order mistakes where the platform is not placed first.
Common situations: Custom scripts that build capArgs dynamically and forget the platform token; CLI wrappers that pass '--target <id>' before the platform; typos like 'iOS'/'Android' with different casing; copying a Vite-only invocation into a cap-vite entry without adding the platform.
Related errors
- cap-vite [vite args...] -- <ios|android> [cap run args...]
- Expected `cap run --list --json` to return a JSON array.
- The first `cap run` argument must be `ios` or `android`.
- AIRI host websocket bridge is unavailable
- Missing value for `${optionName}`.
AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12).
Data as JSON: /api/errors/bfe972d9760ee46c.
Report an issue: GitHub.