jamiepine/voicebox · error · ValueError

Unknown LLM engine: {engine}. Supported: {list(LLM_ENGINES.k

Error message

Unknown LLM engine: {engine}. Supported: {list(LLM_ENGINES.keys())}

What it means

Raised as a ValueError by get_llm_backend_for_engine() when the engine string is not 'qwen_llm' (the only key in LLM_ENGINES). The message interpolates list(LLM_ENGINES.keys()). Like the TTS variant, it is a raw ValueError that will surface as a 500 unless a handler converts it.

Source

Thrown at backend/backends/__init__.py:784

    if engine in _llm_backends:
        return _llm_backends[engine]

    with _llm_backends_lock:
        if engine in _llm_backends:
            return _llm_backends[engine]

        if engine == "qwen_llm":
            backend_type = get_backend_type()
            if backend_type == "mlx":
                from .qwen_llm_backend import MLXQwenLLMBackend

                backend = MLXQwenLLMBackend()
            else:
                from .qwen_llm_backend import PyTorchQwenLLMBackend

                backend = PyTorchQwenLLMBackend()
        else:
            raise ValueError(f"Unknown LLM engine: {engine}. Supported: {list(LLM_ENGINES.keys())}")

        _llm_backends[engine] = backend
        return backend


def reset_backends():
    """Reset backend instances (useful for testing)."""
    global _tts_backend, _tts_backends, _stt_backend, _llm_backends
    _tts_backend = None
    _tts_backends.clear()
    _stt_backend = None
    _llm_backends.clear()

View on GitHub (pinned to 51f49dea19)

Solutions

  1. Validate engine against LLM_ENGINES.keys() before calling get_llm_backend_for_engine().
  2. When adding an LLM engine, add both the LLM_ENGINES entry and the if/elif branch together.
  3. Catch ValueError at the API boundary and return a 400 with the supported list.
  4. Default callers should use get_llm_backend() (hardcoded 'qwen_llm') to avoid ever hitting this.

Example fix

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

Strategy: validation

Validate before calling

from backend.backends import LLM_ENGINES

def assert_valid_llm_engine(engine: str) -> None:
    if engine not in LLM_ENGINES:
        raise ValueError(f'Unsupported LLM engine: {engine}. Supported: {list(LLM_ENGINES)}')

# Prefer the default helper, which always passes qwen_llm:
backend = get_llm_backend()

Type guard

def is_known_llm_engine(engine: str) -> bool:
    return engine in LLM_ENGINES

Try / catch

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

Prevention

When it happens

Trigger: A caller requests an LLM engine other than 'qwen_llm' — e.g. a future 'ollama' or 'llama_cpp' engine wired on the client but not yet implemented, or a typo. The default helper get_llm_backend() always passes 'qwen_llm' and never triggers this.

Common situations: Frontend/backend version skew shipping a new LLM engine selector before backend support. Persisted settings referencing a renamed engine. Exploratory code passing an arbitrary string.

Related errors


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