moeru-ai/airi · error · Error

Invalid model: ${modelId}. Must be one of: ${KOKORO_MODELS.m

Error message

Invalid model: ${modelId}. Must be one of: ${KOKORO_MODELS.map(item => item.id).join(', ')}

What it means

assertModelSupported looks modelId up in the static KOKORO_MODELS catalog and throws when it is absent, listing the valid ids in the message. The id typically comes from persisted settings or caller code, so this fires when a stored id no longer exists in the catalog shipped by the running code.

Source

Thrown at packages/stage-ui/src/libs/providers/providers/kokoro-local/index.ts:45

  'pt-br': { code: 'pt-BR', title: 'Portuguese (Brazil)' },
}

function getWebGpuState() {
  const capabilities = getCachedWebGPUCapabilities()
  return {
    supported: capabilities?.supported ?? (typeof navigator !== 'undefined' && Boolean(navigator.gpu)),
    fp16Supported: capabilities?.fp16Supported ?? false,
  }
}

function getModel(modelId: string) {
  return KOKORO_MODELS.find(model => model.id === modelId)
}

function assertModelSupported(modelId: string) {
  const model = getModel(modelId)
  if (!model)
    throw new Error(`Invalid model: ${modelId}. Must be one of: ${KOKORO_MODELS.map(item => item.id).join(', ')}`)

  if (model.platform === 'webgpu' && !getWebGpuState().supported)
    throw new Error('WebGPU is required for this model but is not available in your browser')

  return model
}

function progressInfo(progress: { file?: string, percent: number, loaded?: number, total?: number }): ProgressInfo {
  return {
    name: progress.file ?? '',
    file: progress.file ?? '',
    progress: progress.percent >= 0 ? progress.percent : 0,
    status: 'progress',
    loaded: progress.loaded ?? 0,
    total: progress.total ?? 0,
  }
}

View on GitHub (pinned to 677329427f)

Solutions

  1. Use one of the ids listed in the error message — it enumerates the current catalog
  2. Re-select the model in the provider settings UI so the current catalog id is persisted
  3. Fall back to the first catalog entry when the persisted id is unknown
  4. Add a settings migration step when model ids change between releases

Example fix

// before
kokoro.speech('kokoro-82m-int8-q4', ...) // id no longer in KOKORO_MODELS

// after
const modelId = KOKORO_MODELS.some(m => m.id === savedId) ? savedId : KOKORO_MODELS[0]!.id
kokoro.speech(modelId, ...)
Defensive patterns

Strategy: validation

Validate before calling

const isValid = KOKORO_MODELS.some(m => m.id === selectedModelId)
if (!isValid)
  selectedModelId = KOKORO_MODELS[0]!.id

Type guard

function isKokoroModelId(id: string): boolean {
  return KOKORO_MODELS.some(m => m.id === id)
}

Try / catch

try {
  assertModelSupported(modelId)
}
catch (err) {
  if (err.message.startsWith('Invalid model:'))
    modelId = KOKORO_MODELS[0]!.id // reset to a valid default and continue
}

Prevention

When it happens

Trigger: A settings record persisted by an older app version references a model id that was renamed or removed; a hardcoded model string has a typo; the catalog changed ids between ONNX and WebGPU variants across releases.

Common situations: App update renamed model variants; importing settings from another machine; manually editing stored provider config.

Related errors


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