{"record":{"id":"ce7de17681f5e615","repo":"can1357/oh-my-pi","slug":"no-local-tts-model-registered-for-key-modelkey","errorCode":null,"errorMessage":"No local TTS model registered for key: ${modelKey ?? DEFAULT_TTS_LOCAL_MODEL_KEY}","messagePattern":"No local TTS model registered for key: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tts/models.ts","lineNumber":122,"sourceCode":"\tvalue: voice.id,\n\tlabel: voice.label,\n})) as ReadonlyArray<{ value: string; label: string }>;\n\n/** Accepted `tts.localVoice` values (default model's catalog) for schema validation. */\nexport const TTS_LOCAL_VOICE_VALUES = KOKORO_VOICES.map(voice => voice.id) as readonly string[];\n\nexport function getTtsLocalModelSpec(key: string): TtsLocalModelSpec | undefined {\n\treturn TTS_LOCAL_MODELS.find(model => model.key === key);\n}\n\nexport function isTtsLocalModelKey(value: string): value is TtsLocalModelKey {\n\treturn getTtsLocalModelSpec(value) !== undefined;\n}\n\n/** Resolve a model key (or the default) to its Hugging Face repo id. */\nexport function resolveTtsRepo(modelKey: string | undefined): string {\n\tconst spec = (modelKey && getTtsLocalModelSpec(modelKey)) || getTtsLocalModelSpec(DEFAULT_TTS_LOCAL_MODEL_KEY);\n\tif (!spec) throw new Error(`No local TTS model registered for key: ${modelKey ?? DEFAULT_TTS_LOCAL_MODEL_KEY}`);\n\treturn spec.repo;\n}\n\n/**\n * Resolve a requested voice id to a concrete voice the model supports, falling\n * back to the model's default voice (first entry) when the id is unknown or the\n * legacy `\"default\"` sentinel. The returned id is always a valid Kokoro voice.\n */\nexport function resolveTtsVoice(modelKey: string | undefined, voice: string | undefined): string {\n\tconst spec = (modelKey && getTtsLocalModelSpec(modelKey)) || getTtsLocalModelSpec(DEFAULT_TTS_LOCAL_MODEL_KEY);\n\tconst fallback = spec?.voices[0]?.id ?? DEFAULT_TTS_VOICE;\n\tif (!spec || !voice) return fallback;\n\tconst match = spec.voices.find(v => v.id === voice);\n\treturn match ? match.id : fallback;\n}\n","sourceCodeStart":104,"sourceCodeEnd":138,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tts/models.ts#L104-L138","documentation":"resolveTtsRepo maps a local TTS model key to its Hugging Face repo id. The key is looked up in the registered model spec table, falling back to the default key (\"kokoro\"); if neither the given key nor the default resolves to a spec, it throws. In practice this means the caller passed an unknown model key AND the default spec table is empty/missing the default entry.","triggerScenarios":"Calling resolveTtsRepo(\"some-model\") where \"some-model\" is not in the local model spec table and getTtsLocalModelSpec(DEFAULT_TTS_LOCAL_MODEL_KEY) also returns undefined; passing undefined relies entirely on the default spec existing.","commonSituations":"A config sets tts.localModel to a typo'd or renamed key; a build/registration bug leaves the spec table unpopulated; a version upgrade removed or renamed a model key still referenced in user settings.","solutions":["Use a registered model key (e.g. \"kokoro\") or unset the config so the default applies","List available keys via the local model spec table (isTtsLocalModel / getTtsLocalModelSpec) and pick a valid one","Check for renames after upgrading — update the tts.localModel setting to the new key","If even the default fails, verify the models.ts spec table is intact (build/registration issue)"],"exampleFix":"// before\nresolveTtsRepo(\"kokoro-82m-v1\"); // unknown key\n// after\nresolveTtsRepo(\"kokoro\"); // registered key (or undefined for default)","handlingStrategy":"fallback","validationCode":"import { isTtsLocalModelKey } from './models';\nconst key = isTtsLocalModelKey(config.tts.localModel) ? config.tts.localModel : undefined; // undefined -> default","typeGuard":"function isValidTtsModelKey(key) {\n  return typeof key === 'string' && isTtsLocalModelKey(key);\n}","tryCatchPattern":"let repo;\ntry {\n  repo = resolveTtsRepo(config.tts.localModel);\n} catch (err) {\n  if (err.message.includes('No local TTS model registered')) {\n    repo = resolveTtsRepo(undefined); // fall back to default model\n  } else throw err;\n}","preventionTips":["Validate tts.localModel against the registered key list at config load time","Use undefined rather than a hand-typed string when you want the default model","After upgrades, re-check for renamed model keys in release notes"],"tags":["tts","configuration","unknown-key","audio"],"backgroundTag":"unknown-enum-value","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}