unclecode/crawl4ai · error · LLMProviderNotAllowed

LLM provider not allowed

Error message

LLM provider not allowed

What it means

resolve_llm in deploy/docker/llm_broker.py raises LLMProviderNotAllowed when the requested provider's family (per _family) is not in allowed_provider_families(config) — the allowlist derived from server config (providers with configured keys plus explicit allow rules). Credentials are server-derived only; a request may pick a provider name but never a base_url/token, so an unapproved provider is rejected outright.

Source

Thrown at deploy/docker/llm_broker.py:57

        fams.add(_family(cfg["provider"]))
    return {f for f in fams if f}


def resolve_llm(config: Dict, requested_provider: Optional[str] = None) -> Dict:
    """Resolve the LLM call parameters fully server-side.

    A request-supplied base_url/api_token is intentionally NOT a parameter here:
    callers pass only the provider *name*. Returns {provider, base_url,
    api_token, temperature}, all server-derived.
    """
    from utils import get_llm_api_key, get_llm_base_url, get_llm_temperature

    default = config["llm"]["provider"]
    provider = requested_provider or default

    fams = allowed_provider_families(config)
    if fams and _family(provider) not in fams:
        raise LLMProviderNotAllowed("LLM provider not allowed")

    return {
        "provider": provider,
        "base_url": get_llm_base_url(config, provider),   # canonical, never from request
        "api_token": get_llm_api_key(config, provider),   # server credential
        "temperature": get_llm_temperature(config, provider),
    }

View on GitHub (pinned to 7e80152142)

Solutions

  1. Check the deployment's LLM config for which providers have API keys/allow entries — allowed_provider_families() is the source of truth.
  2. Request one of the allowed providers, or omit provider to use the configured default.
  3. Operators: add the provider's API key / allow entry in config so its family joins the allowlist.
  4. Catch LLMProviderNotAllowed client-side and surface an 'upgrade/choose provider' message rather than retrying.

Example fix

# before
POST /llm/job {"provider": "gemini", ...}   # deployment allows anthropic only

# after
POST /llm/job {"provider": "anthropic", ...}  # or omit provider for the server default
Defensive patterns

Strategy: type-guard

Validate before calling

from llm_broker import allowed_provider_families, _family

def provider_allowed(config: dict, provider: str | None) -> bool:
    fams = allowed_provider_families(config)
    return not fams or _family(provider or config["llm"]["provider"]) in fams

Type guard

def is_allowed_provider(config, requested) -> bool:
    fams = allowed_provider_families(config)
    return requested is None or (not fams or _family(requested) in fams)

Try / catch

from llm_broker import LLMProviderNotAllowed

try:
    creds = resolve_llm(config, requested_provider)
except LLMProviderNotAllowed:
    creds = resolve_llm(config, None)  # fall back to server default provider

Prevention

When it happens

Trigger: POSTing an extraction job with provider='openai' when the deployment only configures/permits anthropic-family providers; provider='azure-openai' vs 'openai' family mismatch; omitting provider is safe (falls back to config['llm']['provider'], always allowed).

Common situations: Multi-tenant deployments restricting tenants to one vendor; a provider key not set in the server env/config so its family never lands in the allowlist; renaming or adding a provider in config without updating clients.

Related errors


AI-assisted analysis of unclecode/crawl4ai@7e80152142 (2026-08-14). Data as JSON: /api/errors/0a99a6cc1c5b58d4. Report an issue: GitHub.