{"record":{"id":"f7de8f200c215122","repo":"srbhr/Resume-Matcher","slug":"missing-base-url","errorCode":"missing_base_url","errorMessage":"missing_base_url","messagePattern":"missing_base_url","errorType":"http","errorClass":"HTTPException","httpStatus":422,"severity":"error","filePath":"apps/backend/app/routers/config.py","lineNumber":181,"sourceCode":"    if request.reasoning_effort is not None:\n        # Persist empty string on clear so the gpt-5 auto-migration doesn't\n        # re-fire on next get_llm_config() call.\n        stored[\"reasoning_effort\"] = request.reasoning_effort\n\n    # Build normalized config for response and background health check\n    resolved_provider = stored.get(\"provider\", settings.llm_provider)\n\n    # M-05: `requiresBaseUrl` was enforced in the settings UI only, so the\n    # .env-driven path could persist a provider that cannot work without an\n    # endpoint. Fail at save time with a field name instead of surfacing an\n    # opaque LiteLLM error on the user's first generation.\n    if resolved_provider in PROVIDERS_REQUIRING_BASE_URL and not (\n        _effective_api_base(stored)\n    ):\n        # Structured detail using the same {code, field, missing} shape as\n        # update_feature_prompts below, so the UI has one schema to read for\n        # every validation error out of this router.\n        raise HTTPException(\n            status_code=422,\n            detail={\n                \"code\": \"missing_base_url\",\n                \"field\": \"api_base\",\n                \"missing\": [\"api_base\"],\n            },\n        )\n    raw_re = stored.get(\"reasoning_effort\", settings.reasoning_effort)\n    resolved_reasoning_effort = raw_re if raw_re else None\n    test_config = LLMConfig(\n        provider=resolved_provider,\n        model=stored.get(\"model\", settings.llm_model),\n        api_key=resolve_api_key(stored, resolved_provider),\n        api_base=_effective_api_base(stored),\n        reasoning_effort=resolved_reasoning_effort,\n    )\n\n    # Save config regardless of health check outcome (see docstring).","sourceCodeStart":163,"sourceCodeEnd":199,"githubUrl":"https://github.com/srbhr/Resume-Matcher/blob/116f9cc3b00e1ac91734a6c2679bf41ea64a0edc/apps/backend/app/routers/config.py#L163-L199","documentation":"A structured 422 validation error with detail {code:'missing_base_url', field:'api_base', missing:['api_base']} raised by update_llm_config. The selected provider is in PROVIDERS_REQUIRING_BASE_URL (providers that need an explicit API base endpoint) but no api_base is stored or derivable, so the config would be unusable.","triggerScenarios":"PUT/POST the LLM config selecting a provider that requires a base URL (e.g. custom/self-hosted/OpenAI-compatible providers) while the api_base field is empty and no effective base can be resolved from stored config or environment.","commonSituations":"User picks a custom provider in the settings UI but leaves the API base URL blank; migrating configs between environments where the env var supplying the base URL is unset.","solutions":["Provide api_base in the request payload or fill the API base URL field in the UI","Set the environment/config value that supplies the base for the provider","Choose a provider that does not require a base URL if using a hosted default"],"exampleFix":"// before\nawait api.updateLlmConfig({ provider: 'custom' })\n// after\nawait api.updateLlmConfig({ provider: 'custom', api_base: 'https://llm.example.com/v1' })","handlingStrategy":"validation","validationCode":"const REQUIRES_BASE = ['custom','self-hosted','openai-compatible']\nif (REQUIRES_BASE.includes(cfg.provider) && !cfg.api_base) {\n  throw new Error('provider ' + cfg.provider + ' requires api_base')\n}","typeGuard":null,"tryCatchPattern":"try {\n  await api.updateLlmConfig(cfg)\n} catch (e) {\n  const d = e.response?.data?.detail\n  if (d?.code === 'missing_base_url') {\n    highlightField('api_base', 'This provider requires an API base URL')\n  } else throw e\n}","preventionTips":["Require the api_base field in the UI when a base-URL provider is selected","Check the structured detail.code to route validation errors to the right field","Keep base URLs in env/config so they survive provider switches","Test config saves after provider migrations"],"tags":["validation","http-422","llm-config","api-base"],"backgroundTag":"missing-api-base-url","analyzedSha":"116f9cc3b00e1ac91734a6c2679bf41ea64a0edc","analyzedAt":"2026-08-28T22:51:40.999Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}