{"record":{"id":"1dcf1946debb361e","repo":"moeru-ai/airi","slug":"expected-cap-run-list-json-to-return-a-json","errorCode":null,"errorMessage":"Expected `cap run --list --json` to return a JSON array.","messagePattern":"Expected `cap run --list --json` to return a JSON array\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/cap-vite/src/native.ts","lineNumber":98,"sourceCode":"    ['app', 'src', 'main', 'res', 'xml', 'config.xml'],\n    ['app', 'capacitor.build.gradle'],\n    ['capacitor-cordova-android-plugins'],\n    ['capacitor.settings.gradle'],\n  ],\n}\n\nexport function parseCapacitorPlatform(value: string | undefined): CapacitorPlatform | null {\n  return value === 'android' || value === 'ios' ? value : null\n}\n\nexport function hasCapacitorTargetArg(capArgs: string[]): boolean {\n  return capArgs.some((arg, index) => arg === '--target' || (index > 0 && arg.startsWith('--target=')))\n}\n\nfunction parseCapacitorTargetList(value: string): CapacitorTarget[] {\n  const parsed = JSON.parse(value)\n  if (!Array.isArray(parsed)) {\n    throw new TypeError('Expected `cap run --list --json` to return a JSON array.')\n  }\n\n  return parsed\n    .filter((target): target is CapacitorTarget => typeof target === 'object' && target !== null && typeof (target as CapacitorTarget).id === 'string')\n}\n\nasync function listCapacitorTargets(platform: CapacitorPlatform): Promise<CapacitorTarget[]> {\n  const output = await x('cap', ['run', platform, '--list', '--json'])\n\n  return parseCapacitorTargetList(output.stdout)\n}\n\n/**\n * Resolves Capacitor run arguments by applying target defaults.\n *\n * Use when:\n * - `cap-vite` is about to run `cap run`\n * - Callers want env-based device IDs before falling back to the first available target","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/moeru-ai/airi/blob/27111382b4a79a7e983289d6e983a06af185ed0f/packages/cap-vite/src/native.ts#L80-L116","documentation":"Thrown by parseCapacitorTargetList() when `cap run <platform> --list --json` produces output that JSON.parses to something other than an array. The function is the internal parser for listCapacitorTargets(), which shells out to the Capacitor CLI expecting a JSON array of target descriptors.","triggerScenarios":"listCapacitorTargets(platform) is called (transitively from resolveCapRunArgs when no --target and no CAPACITOR_DEVICE_ID env is set), and the `cap` CLI emits a JSON object, a JSON scalar, or non-JSON text such as a warning, deprecation notice, or an error message routed to stdout.","commonSituations":"Capacitor CLI version mismatch where --list --json shape changed or is unsupported; `cap` not installed so the shell returns an error string; a newer/older @capacitor/cli that prints a banner before the JSON; CI environments where the CLI prints auth or telemetry noise to stdout.","solutions":["Run `npx cap run ios --list --json` (or android) manually and confirm it emits a JSON array to stdout.","Upgrade or pin @capacitor/cli to a version known to support --list --json.","Pass --target explicitly (or set CAPACITOR_DEVICE_ID_IOS / CAPACITOR_DEVICE_ID_ANDROID) to bypass the listTargets code path entirely.","Ensure only the JSON payload goes to stdout; redirect any CLI banners/warnings to stderr."],"exampleFix":"// before: relies on `cap run --list --json` shape\nawait runCapVite(viteArgs, ['ios'])\n// after: bypass target discovery with an explicit device id\nprocess.env.CAPACITOR_DEVICE_ID_IOS = deviceId\nawait runCapVite(viteArgs, ['ios'])","handlingStrategy":"validation","validationCode":"// Validate shape before relying on listCapacitorTargets output\nasync function safeListTargets(platform: 'ios' | 'android') {\n  const out = (await import('tinyexec').then(m => m.x('cap', ['run', platform, '--list', '--json']))).stdout\n  let parsed: unknown\n  try { parsed = JSON.parse(out) } catch { throw new Error('cap --list output was not JSON') }\n  if (!Array.isArray(parsed)) throw new Error('cap --list did not return an array')\n  return parsed.filter((t): t is { id: string } => t && typeof t.id === 'string')\n}","typeGuard":"function isTargetList(value: unknown): value is { id: string }[] {\n  return Array.isArray(value) && value.every(t => t !== null && typeof t === 'object' && typeof (t as any).id === 'string')\n}","tryCatchPattern":"try {\n  await runCapVite(viteArgs, ['ios'])\n} catch (error) {\n  if (error instanceof TypeError && error.message.includes('JSON array')) {\n    console.error('Capacitor CLI did not return a target list. Check `cap run ios --list --json`.')\n  }\n}","preventionTips":["Prefer an explicit --target when device discovery is unreliable.","Pin a @capacitor/cli version that supports --list --json in your environment.","Smoke-test `cap run <platform> --list --json` in CI to catch CLI regressions."],"tags":["capacitor","cli","json-parsing","subprocess"],"backgroundTag":null,"analyzedSha":"27111382b4a79a7e983289d6e983a06af185ed0f","analyzedAt":"2026-08-12T18:33:34.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}