{"record":{"id":"2ee31d2cfc4e6a53","repo":"jamiepine/voicebox","slug":"unknown-llm-engine-engine-supported-list-llm","errorCode":null,"errorMessage":"Unknown LLM engine: {engine}. Supported: {list(LLM_ENGINES.keys())}","messagePattern":"Unknown LLM engine: (.+?)\\. Supported: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"backend/backends/__init__.py","lineNumber":784,"sourceCode":"    if engine in _llm_backends:\n        return _llm_backends[engine]\n\n    with _llm_backends_lock:\n        if engine in _llm_backends:\n            return _llm_backends[engine]\n\n        if engine == \"qwen_llm\":\n            backend_type = get_backend_type()\n            if backend_type == \"mlx\":\n                from .qwen_llm_backend import MLXQwenLLMBackend\n\n                backend = MLXQwenLLMBackend()\n            else:\n                from .qwen_llm_backend import PyTorchQwenLLMBackend\n\n                backend = PyTorchQwenLLMBackend()\n        else:\n            raise ValueError(f\"Unknown LLM engine: {engine}. Supported: {list(LLM_ENGINES.keys())}\")\n\n        _llm_backends[engine] = backend\n        return backend\n\n\ndef reset_backends():\n    \"\"\"Reset backend instances (useful for testing).\"\"\"\n    global _tts_backend, _tts_backends, _stt_backend, _llm_backends\n    _tts_backend = None\n    _tts_backends.clear()\n    _stt_backend = None\n    _llm_backends.clear()\n","sourceCodeStart":766,"sourceCodeEnd":797,"githubUrl":"https://github.com/jamiepine/voicebox/blob/51f49dea198384b4eb6087b72c17057c6eb1c1cd/backend/backends/__init__.py#L766-L797","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Validate engine against LLM_ENGINES.keys() before calling get_llm_backend_for_engine().","When adding an LLM engine, add both the LLM_ENGINES entry and the if/elif branch together.","Catch ValueError at the API boundary and return a 400 with the supported list.","Default callers should use get_llm_backend() (hardcoded 'qwen_llm') to avoid ever hitting this."],"exampleFix":"# before\nraise ValueError(f\"Unknown LLM engine: {engine}. Supported: {list(LLM_ENGINES.keys())}\")\n# after\nfrom fastapi import HTTPException\nraise HTTPException(status_code=400, detail=f\"Unknown LLM engine: {engine}. Supported: {list(LLM_ENGINES.keys())}\")","handlingStrategy":"validation","validationCode":"from backend.backends import LLM_ENGINES\n\ndef assert_valid_llm_engine(engine: str) -> None:\n    if engine not in LLM_ENGINES:\n        raise ValueError(f'Unsupported LLM engine: {engine}. Supported: {list(LLM_ENGINES)}')\n\n# Prefer the default helper, which always passes qwen_llm:\nbackend = get_llm_backend()","typeGuard":"def is_known_llm_engine(engine: str) -> bool:\n    return engine in LLM_ENGINES","tryCatchPattern":"from fastapi import HTTPException\ntry:\n    backend = get_llm_backend_for_engine(engine)\nexcept ValueError as e:\n    raise HTTPException(status_code=400, detail=str(e)) from e","preventionTips":["Default callers should use get_llm_backend() (hardcoded 'qwen_llm').","Add the LLM_ENGINES entry and the matching if/elif branch together for new engines.","Catch ValueError at the API boundary and return a 400 with the supported list.","Validate persisted settings referencing an LLM engine after renames."],"tags":["backend","python","fastapi","llm","validation","valueerror","engine-router"],"backgroundTag":null,"analyzedSha":"51f49dea198384b4eb6087b72c17057c6eb1c1cd","analyzedAt":"2026-08-12T16:51:42.824Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}