NousResearch/hermes-agent · error · ValueError
switch_model: no base_url resolved for provider '{new_provid
Error message
switch_model: no base_url resolved for provider '{new_provider}' (switching from '{old_provider}'); refusing to keep the previous provider's endpoint What it means
switch_model refuses to change providers when the new provider's base_url resolves empty. Keeping the previous provider's endpoint would silently send provider B's traffic to provider A's URL, and (per the comment citing #47828) the mis-applied state would persist on every subsequent turn until restart. Re-selecting the SAME provider with an empty base_url (credential-only refresh) is still allowed.
Source
Thrown at agent/agent_runtime_helpers.py:2583
# provider is actually changing, do NOT fall back to the current
# (old provider's) URL — that silently pairs the new provider label
# with the previous provider's endpoint (e.g. new_provider=minimax
# paired with the leftover api.githubcopilot.com URL), and every
# request after the switch 400s at the wrong host. This mismatched
# pair also gets snapshotted into _primary_runtime below, so it
# keeps re-applying on every subsequent turn until a full restart.
# Fail loud instead: the caller (model_switch.switch_model())
# already resolves base_url for every real provider, so an empty
# value here means resolution failed upstream, not that the
# provider genuinely has none. Re-selecting the SAME provider with
# an empty base_url (e.g. a credential-only refresh) is still fine
# to keep the current URL. See #47828.
old_norm_provider = (old_provider or "").strip().lower()
new_norm_provider = (new_provider or "").strip().lower()
if base_url:
agent.base_url = base_url
elif old_norm_provider != new_norm_provider:
raise ValueError(
f"switch_model: no base_url resolved for provider "
f"'{new_provider}' (switching from '{old_provider}'); "
"refusing to keep the previous provider's endpoint"
)
agent.api_mode = api_mode
# Invalidate transport cache — new api_mode may need a different transport
if hasattr(agent, "_transport_cache"):
agent._transport_cache.clear()
if api_key:
agent.api_key = api_key
# ── Reload credential pool for the new provider (issue #52727) ──
# Without this, ``recover_with_credential_pool`` sees a
# ``pool.provider != agent.provider`` mismatch and short-circuits,
# leaving the new provider with no rotation/recovery on 401/429 and
# burning the original pool's entries. Only reload when the provider
# actually changed (or the pool was missing) — re-selecting the same
# provider must not churn the pool reference. A reload failure isView on GitHub (pinned to c896c09c42)
Solutions
- Ensure the target provider's profile (plugins/model-providers/<name>) defines a base_url, or supply model.base_url in config.yaml
- Check the provider name for typos in the `hermes model` selection
- If the switch was meant as a credential-only refresh, keep the provider identical instead of naming a different one
- Update the provider plugin if its ProviderProfile shape changed
Defensive patterns
Strategy: validation
Validate before calling
def can_switch(old_provider: str, new_provider: str, new_base_url) -> bool:
if new_base_url:
return True
return (old_provider or "").strip().lower() == (new_provider or "").strip().lower()
assert can_switch(old_provider, new_provider, resolved_base_url), (
f"refusing switch to {new_provider!r}: no base_url resolved"
) Try / catch
try:
switch_model(new_provider=new_provider, base_url=resolved_url)
except ValueError as e:
if "no base_url resolved" in str(e):
abort_switch_and_keep_current() # current endpoint stays valid
else:
raise Prevention
- Resolve and pass an explicit base_url for every provider switch
- Ensure provider profiles (plugins/model-providers/<name>) always declare a default base_url
- Double-check provider spelling in switch commands — unknown names resolve no endpoint
When it happens
Trigger: model_switch.switch_model() reaches this helper with new_provider differing from old_provider (case-insensitive) while base_url is empty/None — provider-profile resolution produced no default endpoint and none was passed in.
Common situations: A custom provider plugin registered without a default base_url; provider name typo after a plugin rename; config resolving the provider credential-only with no endpoint; provider plugin not yet discovered at switch time.
Related errors
- Provider '{_explicit}' is set in config.yaml but no API key
- No LLM provider configured. Run `hermes model` to select a p
- Malformed custom endpoint URL: {candidate!r}. Run `hermes se
- Invalid profile name: ${value}
- SSH host is required.
AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14).
Data as JSON: /api/errors/c2772f36066bb4e3.
Report an issue: GitHub.