{"record":{"id":"0c0e5ece7ee1ce88","repo":"HKUDS/DeepTutor","slug":"model-is-required","errorCode":null,"errorMessage":"Model is required","messagePattern":"Model is required","errorType":"validation","errorClass":"LLMConfigError","httpStatus":null,"severity":"error","filePath":"deeptutor/services/llm/providers/routing.py","lineNumber":80,"sourceCode":"def _coerce_str(value: object, default: str) -> str:\n    return value if isinstance(value, str) and value else default\n\n\n@register_provider(\"routing\")\nclass RoutingProvider(BaseLLMProvider):\n    \"\"\"Provider that routes between cloud and local function providers.\"\"\"\n\n    def __init__(self, config: LLMConfig) -> None:\n        super().__init__(config)\n        # Use per-route provider name for circuit-breaker/metrics when possible.\n        if is_local_llm_server(self.base_url or \"\"):\n            self.provider_name = \"local\"\n\n    async def complete(self, prompt: str, **kwargs: object) -> TutorResponse:\n        \"\"\"Complete via local_provider/cloud_provider with retries.\"\"\"\n        model = _coerce_str(kwargs.pop(\"model\", None), self.config.model)\n        if not model:\n            raise LLMConfigError(\"Model is required\")\n\n        system_prompt = kwargs.pop(\"system_prompt\", \"You are a helpful assistant.\")\n        messages = kwargs.pop(\"messages\", None)\n        max_retries = _coerce_int(kwargs.pop(\"max_retries\", 3), 3)\n        sleep_value = kwargs.pop(\"sleep\", None)\n        sleep = sleep_value if callable(sleep_value) else None\n\n        use_cache = bool(kwargs.pop(\"use_cache\", True))\n        cache_ttl_seconds = kwargs.pop(\"cache_ttl_seconds\", None)\n        cache_key = kwargs.pop(\"cache_key\", None)\n\n        call_kwargs = {\n            \"prompt\": prompt,\n            \"system_prompt\": system_prompt,\n            \"model\": model,\n            \"api_key\": self.api_key,\n            \"base_url\": self.base_url,\n            \"messages\": messages,","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/services/llm/providers/routing.py#L62-L98","documentation":"The routing provider delegates to local_provider/cloud_provider and needs a model name; neither the `model` kwarg nor the routing config's `model` field provided one. It raises LLMConfigError before attempting any API call, so no network traffic occurs.","triggerScenarios":"Calling RoutingProvider.complete() when the routing config has no default model and the caller omits model=...; the underlying local provider config (e.g. Ollama) was expected to supply a default but routing doesn't read it.","commonSituations":"Misconfigured routing settings JSON where \"model\" is absent, migrating configs after a schema change, assuming the local backend's default model propagates to the router.","solutions":["Set a default model on the routing provider's config.","Pass model=\"...\" in the complete() kwargs.","Verify the settings file (data/user/settings) for the routing/local provider actually contains a model key."],"exampleFix":"# before\nawait router.complete(\"hi\")  # LLMConfigError\n\n# after\nawait router.complete(\"hi\", model=\"llama3.1\")","handlingStrategy":"validation","validationCode":"if not (kwargs.get(\"model\") or router.config.model):\n    raise LLMConfigError(\"Model is required\")","typeGuard":"def _coerce_str(v, default):\n    if isinstance(v, str) and v.strip():\n        return v\n    return default","tryCatchPattern":"from deeptutor.services.llm.errors import LLMConfigError\ntry:\n    resp = await router.complete(prompt, model=resolved_model)\nexcept LLMConfigError:\n    # config problem — fix settings, do not retry\n    raise","preventionTips":["Resolve the model once at startup from config/env and pass it explicitly.","Add a settings schema check that requires model for routing providers.","Write a smoke test that calls complete() on app boot."],"tags":["routing","config","missing-model","llm"],"backgroundTag":"missing-model-config","analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}