srbhr/Resume-Matcher · error · HTTPException

missing_base_url

missing_base_url

Error message

missing_base_url

What it means

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.

Source

Thrown at apps/backend/app/routers/config.py:181

    if request.reasoning_effort is not None:
        # Persist empty string on clear so the gpt-5 auto-migration doesn't
        # re-fire on next get_llm_config() call.
        stored["reasoning_effort"] = request.reasoning_effort

    # Build normalized config for response and background health check
    resolved_provider = stored.get("provider", settings.llm_provider)

    # M-05: `requiresBaseUrl` was enforced in the settings UI only, so the
    # .env-driven path could persist a provider that cannot work without an
    # endpoint. Fail at save time with a field name instead of surfacing an
    # opaque LiteLLM error on the user's first generation.
    if resolved_provider in PROVIDERS_REQUIRING_BASE_URL and not (
        _effective_api_base(stored)
    ):
        # Structured detail using the same {code, field, missing} shape as
        # update_feature_prompts below, so the UI has one schema to read for
        # every validation error out of this router.
        raise HTTPException(
            status_code=422,
            detail={
                "code": "missing_base_url",
                "field": "api_base",
                "missing": ["api_base"],
            },
        )
    raw_re = stored.get("reasoning_effort", settings.reasoning_effort)
    resolved_reasoning_effort = raw_re if raw_re else None
    test_config = LLMConfig(
        provider=resolved_provider,
        model=stored.get("model", settings.llm_model),
        api_key=resolve_api_key(stored, resolved_provider),
        api_base=_effective_api_base(stored),
        reasoning_effort=resolved_reasoning_effort,
    )

    # Save config regardless of health check outcome (see docstring).

View on GitHub (pinned to 116f9cc3b0)

Solutions

  1. Provide api_base in the request payload or fill the API base URL field in the UI
  2. Set the environment/config value that supplies the base for the provider
  3. Choose a provider that does not require a base URL if using a hosted default

Example fix

// before
await api.updateLlmConfig({ provider: 'custom' })
// after
await api.updateLlmConfig({ provider: 'custom', api_base: 'https://llm.example.com/v1' })
Defensive patterns

Strategy: validation

Validate before calling

const REQUIRES_BASE = ['custom','self-hosted','openai-compatible']
if (REQUIRES_BASE.includes(cfg.provider) && !cfg.api_base) {
  throw new Error('provider ' + cfg.provider + ' requires api_base')
}

Try / catch

try {
  await api.updateLlmConfig(cfg)
} catch (e) {
  const d = e.response?.data?.detail
  if (d?.code === 'missing_base_url') {
    highlightField('api_base', 'This provider requires an API base URL')
  } else throw e
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of srbhr/Resume-Matcher@116f9cc3b0 (2026-08-28). Data as JSON: /api/errors/f7de8f200c215122. Report an issue: GitHub.