invoke-ai/InvokeAI · error · HTTPException

No external provider config fields provided

Error message

No external provider config fields provided

What it means

set_external_provider_config returns 400 when the request body contains no fields that actually map to external-provider config keys (e.g. api_key / base_url for the provider). After building the updates dict from update.api_key/update.base_url, an empty dict means nothing was provided, so the server refuses the no-op call.

Source

Thrown at invokeai/app/api/routers/app_info.py:331

    response_model=ExternalProviderConfigModel,
)
def set_external_provider_config(
    _: AdminUserOrDefault,
    provider_id: str = Path(description="The external provider identifier"),
    update: ExternalProviderConfigUpdate = Body(description="External provider configuration settings"),
) -> ExternalProviderConfigModel:
    api_key_field, base_url_field = _get_external_provider_fields(provider_id)
    updates: dict[str, str | None] = {}

    if update.api_key is not None:
        api_key = update.api_key.strip()
        updates[api_key_field] = api_key or None
    if update.base_url is not None:
        base_url = update.base_url.strip()
        updates[base_url_field] = base_url or None

    if not updates:
        raise HTTPException(status_code=400, detail="No external provider config fields provided")

    api_key_removed = update.api_key is not None and updates.get(api_key_field) is None
    _apply_external_provider_update(updates)
    if api_key_removed:
        _remove_external_models_for_provider(provider_id)
    return _build_external_provider_config(provider_id, get_config())


@app_router.delete(
    "/external_providers/config/{provider_id}",
    operation_id="reset_external_provider_config",
    status_code=200,
    response_model=ExternalProviderConfigModel,
)
def reset_external_provider_config(
    _: AdminUserOrDefault,
    provider_id: str = Path(description="The external provider identifier"),
) -> ExternalProviderConfigModel:

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Include at least one real field in the body: api_key and/or base_url
  2. To CLEAR a field send an empty string ("") rather than null (empty string maps to None and counts as an update)
  3. Fix the client to omit the call entirely when nothing changed
  4. Check which fields the target provider supports via its config schema and send one of those

Example fix

// before
await fetch(url, { method: 'POST', body: JSON.stringify({ api_key: null, base_url: null }) });
// after
await fetch(url, { method: 'POST', body: JSON.stringify({ api_key: 'sk-...' }) });
Defensive patterns

Strategy: validation

Validate before calling

def validate_provider_update(update: dict) -> bool:
    fields = {'api_key', 'base_url'}
    return any(update.get(f) is not None for f in fields)  # at least one real value

if not validate_provider_update(payload):
    raise ValueError('Supply api_key and/or base_url (use "" to clear)')

Type guard

def has_provider_field(update: dict) -> bool:
    return isinstance(update, dict) and any(
        v is not None for k, v in update.items() if k in ('api_key', 'base_url')
    )

Try / catch

try:
    resp = requests.post(url, json=payload)
    resp.raise_for_status()
except requests.HTTPError as e:
    if e.response.status_code == 400 and 'No external provider' in e.response.json().get('detail', ''):
        skip_call = True  # nothing to update

Prevention

When it happens

Trigger: POSTing to the external-provider config endpoint with a body where every optional field is None/absent (e.g. {} or {"api_key": null, "base_url": null}), so `updates` stays empty.

Common situations: Frontend sending an untouched form; client serializing all-None optional fields; a provider whose only fields are api_key/base_url both left blank; generic code paths reusing a payload template across providers.

Related errors


AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29). Data as JSON: /api/errors/c6d0e8c9969b9a69. Report an issue: GitHub.