moeru-ai/airi · error · Error

Kokoro worker did not return voice metadata

Error message

Kokoro worker did not return voice metadata

What it means

Thrown after a successful Kokoro model load when the worker response's metadata.voices field is null/undefined. The worker completed readiness (state set to 'ready', allocation token requested, manifest recorded) but did not return the voice catalog the adapter needs. This indicates the worker bundle/model is incomplete or a version skew between adapter and worker protocol.

Source

Thrown at packages/stage-ui/src/libs/inference/adapters/kokoro.ts:403

        voices = (response.metadata?.voices as Voices) ?? null

        // Track GPU memory allocation
        const coordinator = getGPUCoordinator()
        if (allocationToken)
          coordinator.release(allocationToken)
        const estimateKey = `kokoro-${quantization}`
        const estimated = MODEL_VRAM_ESTIMATES[estimateKey] ?? 165 * 1024 * 1024
        allocationToken = coordinator.requestAllocation(`kokoro-${quantization}`, estimated)

        // Record manifest so consumers can inspect how the adapter resolved
        // device selection after fallback / WASM promotion.
        lastManifest = { quantization, device: (response.device ?? effectiveDevice) as string }

        state = 'ready'
        updateInferenceStatus(modelStatusId, { state: 'ready', device: (response.device ?? effectiveDevice) as any })
        onSuccess()
        if (!voices)
          throw new Error('Kokoro worker did not return voice metadata')
        return voices
      }, { signal: options?.signal })
    }), { quantization, device: effectiveDevice }).catch((error) => {
      // Don't route AbortError through handleWorkerError — cancellation is
      // not a worker failure and shouldn't trigger restart logic.
      if ((error as Error)?.name === 'AbortError')
        throw error
      handleWorkerError(error instanceof Error ? error : new Error(String(error)))
      throw error
    })
  }

  async function generate(
    text: string,
    voice: VoiceKey,
    options?: { signal?: AbortSignal },
  ): Promise<ArrayBuffer> {
    throwIfAborted(options?.signal)

View on GitHub (pinned to 27111382b4)

Solutions

  1. Clear the cached Kokoro model artifacts and reload so the worker re-fetches a complete bundle including voices metadata.
  2. Ensure the worker build version matches the adapter version so the response.metadata.voices contract holds.
  3. Try a different quantization to rule out a quantization-specific missing-manifest defect.
  4. If running a custom model, confirm it ships the voice metadata the worker expects.
Defensive patterns

Strategy: validation

Validate before calling

// after loadModel resolves, sanity-check voices before exposing the adapter
if (!voices || Object.keys(voices).length === 0) {
  // clear model cache and reload; do not surface 'ready' to callers
}

Type guard

function hasVoices(v: unknown): v is Record<string, unknown> {
  return !!v && typeof v === 'object' && Object.keys(v as object).length > 0
}

Try / catch

try {
  const voices = await adapter.loadModel()
}
catch (err) {
  if (err instanceof Error && err.message === 'Kokoro worker did not return voice metadata') {
    // clear cached model artifacts and retry once; if it persists, report worker/model version skew
  }
  else throw err
}

Prevention

When it happens

Trigger: Inside loadModel's readyPromise, response.metadata?.voices resolves to null/undefined. The worker loaded weights and reported a device, but the voices manifest was stripped or never produced — e.g. a corrupted model fetch, a quantization variant without voice metadata, or a worker build that omits the metadata field.

Common situations: Model files partially downloaded or cached from a prior failed fetch. A custom Kokoro model without the voices.json manifest. Worker bundle downgraded/upgraded independently of the adapter so the message shape changed. WASM-fallback path that drops metadata.

Related errors


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