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
- Clear the cached Kokoro model artifacts and reload so the worker re-fetches a complete bundle including voices metadata.
- Ensure the worker build version matches the adapter version so the response.metadata.voices contract holds.
- Try a different quantization to rule out a quantization-specific missing-manifest defect.
- 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
- Keep the Kokoro worker bundle and adapter versioned together so the metadata contract holds.
- Use complete model artifacts that ship the voices manifest.
- Clear the model cache after a failed load to avoid reusing an incomplete bundle.
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
- [${errorCode}] Unexpected output action: ${output.action}
- Web worker transport is not available in node runtime.
- Web worker transport is not implemented yet.
- Missing input text for Gemini TTS
- Missing model for Gemini TTS
AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12).
Data as JSON: /api/errors/914e6df3621d2f8a.
Report an issue: GitHub.