{"record":{"id":"2459db14fd73d85d","repo":"jamiepine/voicebox","slug":"unknown-tts-engine-engine-supported-list-tts","errorCode":null,"errorMessage":"Unknown TTS engine: {engine}. Supported: {list(TTS_ENGINES.keys())}","messagePattern":"Unknown TTS engine: (.+?)\\. Supported: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"backend/backends/__init__.py","lineNumber":727,"sourceCode":"            backend = ChatterboxTTSBackend()\n        elif engine == \"chatterbox_turbo\":\n            from .chatterbox_turbo_backend import ChatterboxTurboTTSBackend\n\n            backend = ChatterboxTurboTTSBackend()\n        elif engine == \"tada\":\n            from .hume_backend import HumeTadaBackend\n\n            backend = HumeTadaBackend()\n        elif engine == \"kokoro\":\n            from .kokoro_backend import KokoroTTSBackend\n\n            backend = KokoroTTSBackend()\n        elif engine == \"qwen_custom_voice\":\n            from .qwen_custom_voice_backend import QwenCustomVoiceBackend\n\n            backend = QwenCustomVoiceBackend()\n        else:\n            raise ValueError(f\"Unknown TTS engine: {engine}. Supported: {list(TTS_ENGINES.keys())}\")\n\n        _tts_backends[engine] = backend\n        return backend\n\n\ndef get_stt_backend() -> STTBackend:\n    \"\"\"\n    Get or create STT backend instance based on platform.\n\n    Returns:\n        STT backend instance (MLX or PyTorch)\n    \"\"\"\n    global _stt_backend\n\n    if _stt_backend is None:\n        backend_type = get_backend_type()\n\n        if backend_type == \"mlx\":","sourceCodeStart":709,"sourceCodeEnd":745,"githubUrl":"https://github.com/jamiepine/voicebox/blob/51f49dea198384b4eb6087b72c17057c6eb1c1cd/backend/backends/__init__.py#L709-L745","documentation":"Raised as a ValueError by get_tts_backend_for_engine() when the requested engine string matches none of the branches in the if/elif chain (qwen, luxtts, chatterbox, chatterbox_turbo, tada, kokoro, qwen_custom_voice). The message interpolates list(TTS_ENGINES.keys()) so the caller sees the accepted values. Because this is a ValueError (not an HTTPException), it surfaces as an unhandled 500 unless a route handler catches it.","triggerScenarios":"A client or internal call passes an engine string not in TTS_ENGINES — typo, stale value, or a frontend/backend version skew where the UI sends an engine the backend doesn't recognize yet.","commonSituations":"Frontend upgraded to support a new engine before the backend. A persisted voice profile references an engine name that was renamed or removed. A test/REPL call with a mistyped engine. Adding a new engine to TTS_ENGINES but forgetting the if/elif branch (or vice versa).","solutions":["Validate the engine against TTS_ENGINES.keys() before calling get_tts_backend_for_engine().","Keep TTS_ENGINES and the if/elif chain in sync — a new entry in the dict needs a matching branch.","Catch ValueError at the API layer and return a 400 with the supported list instead of letting it 500.","Audit persisted voice profiles / settings for stale engine names after renames."],"exampleFix":"# before\nraise ValueError(f\"Unknown TTS engine: {engine}. Supported: {list(TTS_ENGINES.keys())}\")\n# after\nfrom fastapi import HTTPException\nraise HTTPException(status_code=400, detail=f\"Unknown TTS engine: {engine}. Supported: {list(TTS_ENGINES.keys())}\")","handlingStrategy":"validation","validationCode":"from backend.backends import TTS_ENGINES\n\ndef assert_valid_tts_engine(engine: str) -> None:\n    if engine not in TTS_ENGINES:\n        raise ValueError(f'Unsupported TTS engine: {engine}. Supported: {list(TTS_ENGINES)}')\n\ndef get_tts_backend_for_engine_safe(engine: str):\n    assert_valid_tts_engine(engine)\n    return get_tts_backend_for_engine(engine)","typeGuard":"from typing import TypedDict\nclass EngineSpec(TypedDict):\n    engine: str\n    model_size: str\n\ndef is_known_tts_engine(spec: EngineSpec) -> bool:\n    return spec['engine'] in TTS_ENGINES","tryCatchPattern":"from fastapi import HTTPException, Request\ntry:\n    backend = get_tts_backend_for_engine(engine)\nexcept ValueError as e:\n    raise HTTPException(status_code=400, detail=str(e)) from e","preventionTips":["Validate engine against TTS_ENGINES.keys() before resolving the backend.","Keep TTS_ENGINES and the if/elif factory branch in sync when adding engines.","Catch ValueError at the API boundary and return 400, not 500.","Migrate persisted voice profiles after renaming an engine."],"tags":["backend","python","fastapi","tts","validation","valueerror","engine-router"],"backgroundTag":null,"analyzedSha":"51f49dea198384b4eb6087b72c17057c6eb1c1cd","analyzedAt":"2026-08-12T16:51:42.824Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}