{"record":{"id":"a35f22350c07802d","repo":"HKUDS/DeepTutor","slug":"base-url-is-required-for-local-llm-provider","errorCode":null,"errorMessage":"base_url is required for local LLM provider","messagePattern":"base_url is required for local LLM provider","errorType":"validation","errorClass":"LLMConfigError","httpStatus":null,"severity":"error","filePath":"deeptutor/services/llm/local_provider.py","lineNumber":177,"sourceCode":"    \"\"\"\n    Complete a prompt using local LLM server.\n\n    Uses aiohttp for better compatibility with local servers.\n\n    Args:\n        prompt: The user prompt (ignored if messages provided)\n        system_prompt: System prompt for context\n        model: Model name\n        api_key: API key (optional for most local servers)\n        base_url: Base URL for the local server\n        messages: Pre-built messages array (optional)\n        **kwargs: Additional parameters (temperature, max_tokens, etc.)\n\n    Returns:\n        str: The LLM response\n    \"\"\"\n    if not base_url:\n        raise LLMConfigError(\"base_url is required for local LLM provider\")\n\n    # Sanitize URL and build chat endpoint\n    base_url = sanitize_url(base_url, model or \"\")\n    url = build_chat_url(base_url)\n\n    # Build headers using unified utility\n    headers = build_auth_headers(api_key)\n\n    # Build messages\n    if messages:\n        msg_list = messages\n    else:\n        msg_list = [\n            {\"role\": \"system\", \"content\": system_prompt},\n            {\"role\": \"user\", \"content\": prompt},\n        ]\n\n    # Build request data","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/services/llm/local_provider.py#L159-L195","documentation":"The local LLM provider (Ollama/llama.cpp-style backends) requires an explicit base_url because there is no default endpoint to call. complete() raises LLMConfigError before any HTTP request when base_url is empty, since it cannot construct the chat completions URL.","triggerScenarios":"Calling LocalLLMProvider.complete(prompt) (or stream(), which delegates to complete) with base_url=None or '' — e.g. config missing the 'base_url' key, env var LOCAL_LLM_BASE_URL unset, or a settings JSON where the field name is misspelled.","commonSituations":"Fresh installs where the local provider config was never filled in; switching from OpenAI to a local backend without adding the URL; loading settings from data/user/settings/*.json that predates the base_url field.","solutions":["Set base_url in the provider config (e.g. http://localhost:11434/v1 for Ollama) and restart.","Check the settings JSON under data/user/settings/ for a missing/typo'd base_url key.","Verify the local server is actually running and the URL matches its API path."],"exampleFix":"# before\nprovider = LocalLLMProvider(config={'model': 'llama3'})\n# after\nprovider = LocalLLMProvider(config={'model': 'llama3', 'base_url': 'http://localhost:11434/v1'})","handlingStrategy":"validation","validationCode":"from urllib.parse import urlparse\n\ndef can_use_local_provider(cfg: dict) -> bool:\n    url = cfg.get('base_url')\n    return bool(url) and bool(urlparse(url).scheme) and bool(urlparse(url).netloc)","typeGuard":null,"tryCatchPattern":"from deeptutor.services.llm.local_provider import LLMConfigError\ntry:\n    resp = await provider.complete(prompt)\nexcept LLMConfigError as e:\n    if 'base_url' in str(e):\n        raise SystemExit('Configure LOCAL_LLM_BASE_URL before running') from e\n    raise","preventionTips":["Fail fast at startup with a settings schema check requiring base_url for local providers","Keep one validated settings template per provider","Add a health-check ping to the local server during app bootstrap"],"tags":["config","local-llm","missing-url"],"backgroundTag":"missing-required-config","analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}