jamiepine/voicebox · error · ValueError

Unknown TTS engine: {engine}. Supported: {list(TTS_ENGINES.k

Error message

Unknown TTS engine: {engine}. Supported: {list(TTS_ENGINES.keys())}

What it means

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.

Source

Thrown at backend/backends/__init__.py:727

            backend = ChatterboxTTSBackend()
        elif engine == "chatterbox_turbo":
            from .chatterbox_turbo_backend import ChatterboxTurboTTSBackend

            backend = ChatterboxTurboTTSBackend()
        elif engine == "tada":
            from .hume_backend import HumeTadaBackend

            backend = HumeTadaBackend()
        elif engine == "kokoro":
            from .kokoro_backend import KokoroTTSBackend

            backend = KokoroTTSBackend()
        elif engine == "qwen_custom_voice":
            from .qwen_custom_voice_backend import QwenCustomVoiceBackend

            backend = QwenCustomVoiceBackend()
        else:
            raise ValueError(f"Unknown TTS engine: {engine}. Supported: {list(TTS_ENGINES.keys())}")

        _tts_backends[engine] = backend
        return backend


def get_stt_backend() -> STTBackend:
    """
    Get or create STT backend instance based on platform.

    Returns:
        STT backend instance (MLX or PyTorch)
    """
    global _stt_backend

    if _stt_backend is None:
        backend_type = get_backend_type()

        if backend_type == "mlx":

View on GitHub (pinned to 51f49dea19)

Solutions

  1. Validate the engine against TTS_ENGINES.keys() before calling get_tts_backend_for_engine().
  2. Keep TTS_ENGINES and the if/elif chain in sync — a new entry in the dict needs a matching branch.
  3. Catch ValueError at the API layer and return a 400 with the supported list instead of letting it 500.
  4. Audit persisted voice profiles / settings for stale engine names after renames.

Example fix

# before
raise ValueError(f"Unknown TTS engine: {engine}. Supported: {list(TTS_ENGINES.keys())}")
# after
from fastapi import HTTPException
raise HTTPException(status_code=400, detail=f"Unknown TTS engine: {engine}. Supported: {list(TTS_ENGINES.keys())}")
Defensive patterns

Strategy: validation

Validate before calling

from backend.backends import TTS_ENGINES

def assert_valid_tts_engine(engine: str) -> None:
    if engine not in TTS_ENGINES:
        raise ValueError(f'Unsupported TTS engine: {engine}. Supported: {list(TTS_ENGINES)}')

def get_tts_backend_for_engine_safe(engine: str):
    assert_valid_tts_engine(engine)
    return get_tts_backend_for_engine(engine)

Type guard

from typing import TypedDict
class EngineSpec(TypedDict):
    engine: str
    model_size: str

def is_known_tts_engine(spec: EngineSpec) -> bool:
    return spec['engine'] in TTS_ENGINES

Try / catch

from fastapi import HTTPException, Request
try:
    backend = get_tts_backend_for_engine(engine)
except ValueError as e:
    raise HTTPException(status_code=400, detail=str(e)) from e

Prevention

When it happens

Trigger: 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.

Common situations: 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).

Related errors


AI-assisted analysis of jamiepine/voicebox@51f49dea19 (2026-08-12). Data as JSON: /api/errors/2459db14fd73d85d. Report an issue: GitHub.