moeru-ai/airi · error · Error

CAP_VITE_CAP_ARGS_JSON must be a JSON string array.

Error message

CAP_VITE_CAP_ARGS_JSON must be a JSON string array.

What it means

The generated wrapper config parses the CAP_VITE_CAP_ARGS_JSON environment variable, which runCapVite sets via JSON.stringify(capArgs). It throws when the variable is set but is not a JSON array whose elements are all strings — usually someone set it by hand or double-encoded it.

Solutions

  1. Set it as a JSON string array: CAP_VITE_CAP_ARGS_JSON='["ios","--target","iPhone 16 Pro"]'
  2. Better: don't set it manually — invoke via `cap-vite -- ios ...` or runCapVite(), which serializes capArgs correctly
  3. Unset the variable when running plain vite builds that don't go through the wrapper

Example fix

# before
CAP_VITE_CAP_ARGS_JSON='ios --target "iPhone 16 Pro"' vite --config .cap-vite.config.ts

# after
CAP_VITE_CAP_ARGS_JSON='["ios","--target","iPhone 16 Pro"]' vite --config .cap-vite.config.ts
Defensive patterns

Strategy: validation

Validate before calling

// When setting the env yourself, always serialize an array of strings
process.env.CAP_VITE_CAP_ARGS_JSON = JSON.stringify(['ios', '--target', 'iPhone 16 Pro'])

Type guard

function isStringArray(v: unknown): v is string[] {
  return Array.isArray(v) && v.every(x => typeof x === 'string')
}

Prevention

When it happens

Trigger: Setting CAP_VITE_CAP_ARGS_JSON='ios --target x' (a plain string, not JSON), '["ios", 1]' (non-string element), or a JSON.stringify-ed string that gets stringified again (double encoding). Running the wrapper vite config directly with a stale/incorrect env value.

Common situations: Manually invoking `vite --config <wrapper>` in CI and hand-writing the env var; env value carried over from a different tooling version; quoting layers in YAML/scripts mangling the JSON.

Related errors


AI-assisted analysis of moeru-ai/airi@677329427f (2026-08-18). Data as JSON: /api/errors/2ade96e160f2fb4a. Report an issue: GitHub.

Appendix: source

Thrown at packages/cap-vite/src/vite-wrapper-config.ts:15

import process from 'node:process'

import { defineConfig, loadConfigFromFile, mergeConfig } from 'vite'

import { capVitePlugin } from './vite-plugin'

function parseCapArgs(): string[] {
  const value = process.env.CAP_VITE_CAP_ARGS_JSON
  if (!value) {
    return []
  }

  const parsed = JSON.parse(value)
  if (!Array.isArray(parsed) || parsed.some(arg => typeof arg !== 'string')) {
    throw new Error('CAP_VITE_CAP_ARGS_JSON must be a JSON string array.')
  }

  return parsed
}

function parseConfigLoader(): 'bundle' | 'native' | 'runner' | undefined {
  const value = process.env.CAP_VITE_CONFIG_LOADER
  if (value === 'bundle' || value === 'native' || value === 'runner') {
    return value
  }

  return undefined
}

export default defineConfig(async (env) => {
  const root = process.env.CAP_VITE_ROOT ?? process.cwd()
  const baseConfigFile = process.env.CAP_VITE_BASE_CONFIG || undefined
  const configLoader = parseConfigLoader()

View on GitHub (pinned to 677329427f)