{"record":{"id":"380f260aba6d3925","repo":"harry0703/MoneyPrinterTurbo","slug":"llm-provider-unsupported-llm-provider","errorCode":null,"errorMessage":"{llm_provider}: unsupported llm provider","messagePattern":"(.+?): unsupported llm provider","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"app/services/llm.py","lineNumber":151,"sourceCode":"        if content is not None:\n            return _normalize_text_response(content, \"qwen\")\n\n    text = _get_response_field(output, \"text\") if output else None\n    return _normalize_text_response(text, \"qwen\")\n\n\ndef _generate_response(prompt: str, app_config=None) -> str:\n    try:\n        # WebUI 在视频生成期间允许用户准备下一条文案。调用方可以传入提交瞬间\n        # 的配置快照，确保模型请求重试期间不会因为后台任务结束并应用新配置，\n        # 而切换到另一个 Provider、Base URL 或模型。\n        runtime_app_config = app_config if app_config is not None else config.app\n        llm_provider = str(\n            runtime_app_config.get(\"llm_provider\", DEFAULT_LLM_PROVIDER_ID)\n        ).lower()\n        provider = get_llm_provider(llm_provider)\n        if provider is None:\n            raise ValueError(f\"{llm_provider}: unsupported llm provider\")\n\n        logger.info(f\"llm provider: {llm_provider}\")\n        api_key = runtime_app_config.get(provider.config_key(\"api_key\"), \"\")\n        configured_model = runtime_app_config.get(provider.config_key(\"model_name\"), \"\")\n        model_name = provider.resolve_model_name(configured_model)\n        if configured_model and model_name != configured_model:\n            logger.warning(\n                f\"{llm_provider} model '{configured_model}' is deprecated, \"\n                f\"fallback to '{model_name}'\"\n            )\n        configured_base_url = runtime_app_config.get(\n            provider.config_key(\"base_url\"), \"\"\n        )\n        base_url = provider.resolve_base_url(configured_base_url)\n        if configured_base_url and configured_base_url.strip().rstrip(\"/\") in {\n            url.rstrip(\"/\") for url in provider.deprecated_base_urls\n        }:\n            logger.warning(","sourceCodeStart":133,"sourceCodeEnd":169,"githubUrl":"https://github.com/harry0703/MoneyPrinterTurbo/blob/1f9f19c2021a68d04df228f33e9099a0c947f6f8/app/services/llm.py#L133-L169","documentation":"Provider-resolution failure in _generate_response: get_llm_provider(llm_provider) returned None, meaning the value from config's llm_provider key (lowercased) does not match any registered provider. Raised before any credential checks, so it is purely a config-name mismatch.","triggerScenarios":"Setting llm_provider in config.toml (or the WebUI config snapshot) to a string that is not a registered provider id — typo like 'opena', removed provider after an upgrade, or a custom provider id never registered via the provider registry.","commonSituations":"Typos in config.toml, renaming of provider ids between app versions, users copying config snippets from tutorials that reference plugins not installed, or an app_config snapshot queued with a stale provider id.","solutions":["List the valid provider ids from the provider registry (the same table get_llm_provider consults) and correct llm_provider in config.toml","Check for case/whitespace: the value is lowercased before lookup, but trailing spaces in TOML strings survive","If the id comes from a queued config snapshot, validate it at submission time in the WebUI","After upgrades, re-read the config docs — provider ids may have been renamed"],"exampleFix":"# config.toml before\nllm_provider = \"openai-compat\"  # not a registered id\n\n# config.toml after\nllm_provider = \"openai\"\n\n# defensive check at enqueue time\nprovider = get_llm_provider(str(snapshot.get(\"llm_provider\", \"\")).lower())\nif provider is None:\n    raise ValueError(\"unknown llm_provider in submitted config\")","handlingStrategy":"validation","validationCode":"provider = get_llm_provider(str(cfg.get(\"llm_provider\", \"\")).lower())\nif provider is None:\n    raise ValueError(f\"unknown llm_provider; valid: {list_provider_ids()}\")","typeGuard":"def is_known_provider(name: str) -> bool:\n    return get_llm_provider(str(name).lower()) is not None","tryCatchPattern":null,"preventionTips":["Validate llm_provider at config-save time, not at generation time","Keep a enum/dropdown in the UI instead of free-text provider entry"],"tags":["configuration","llm","provider-registry"],"backgroundTag":null,"analyzedSha":"1f9f19c2021a68d04df228f33e9099a0c947f6f8","analyzedAt":"2026-08-14T19:41:05.568Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}