An Agent Zero LiteLLM model error is more often a prefix or a role problem than a key problem, because Agent Zero never sends the model name you typed. On agent0ai/agent-zero main, models.py builds f"{provider}/{model}" before every LiteLLM call — line 385 for chat, line 800 for embedding — and the provider half comes from conf/model_providers.yaml, not from the dropdown label.
Two version facts decide what the rest means. The latest release is v2.12, published September 9, 2026, and the old frdel/agent-zero path now resolves to agent0ai/agent-zero, so older clone commands and issue links hit a redirect. And requirements.txt pins litellm==1.88.1, commented # CVE-2026-42271 fix: patched floor is 1.83.7. PyPI dates that to June 9, 2026 against a current 1.102.0 from September 20, 2026. Check symptoms against 1.88.1, not LiteLLM's current docs. All checked September 21, 2026.
Read the status code before you touch the key
When the exception carries an integer status code, _is_transient_litellm_error decides on that alone: true for 408, 429, 500, 502, 503 and 504, true for any other 5xx, false for every other status. Only when no status code is present does it fall back to matching exception classes — timeouts and connection errors among them — so "no status" is the one case where a retry can happen without a 4xx/5xx to point at. Every class in the table below carries a status, and they were read inside the litellm 1.88.1 wheel.
| Class in litellm 1.88.1 | Status | What it usually means here | Retried? |
|---|---|---|---|
AuthenticationError | 401 | The endpoint rejected the credential, or none arrived | No |
BadRequestError | 400 | Includes both provider-resolution failures below | No |
LiteLLMUnknownProvider (subclasses BadRequestError) | 400 | A prefix LiteLLM has no route for on this endpoint | No |
ContextWindowExceededError (subclasses BadRequestError) | 400 | Too much context, not a bad id | No |
NotFoundError | 404 | Wrong path on the base URL, or an id the endpoint does not serve | No |
RateLimitError | 429 | Throttled upstream | Yes |
ServiceUnavailableError, InternalServerError | 5xx | Upstream fault | Yes |
One exception and one blind spot. models.py line 638 raises rather than retries when got_any_chunk is true, so a transient error arriving mid-stream is not retried — "it failed immediately" is a hint, not a proof. And configure_litellm() runs at import, setting LITELLM_LOG=ERROR and litellm.suppress_debug_info = True. In 1.88.1 the provider-list hint in get_llm_provider_logic.py is guarded by if litellm.suppress_debug_info is False — the one line LiteLLM would print to point you at its provider list is the line Agent Zero turns off.
The id you typed is not the id that is sent
Two identifiers exist per provider, and the provider config header says so: the provider ID drives "the settings UI dropdowns" and the API-key environment variable, while litellm_provider is "The corresponding provider name in LiteLLM". The second is what gets prepended. For a third-party OpenAI-compatible endpoint the provider id is other ("Other OpenAI compatible"), whose litellm_provider is openai, and _adjust_call_args remaps other to openai too. The wire value is openai/<your-model>, the form LiteLLM documents. So type the bare id: reading those two code sites, adding the prefix yourself would yield openai/openai/gpt-4o — reasoning about the code, not an observed error.
When resolution fails, 1.88.1 has two distinct strings, both 400s. get_llm_provider_logic.py raises BadRequestError with "LLM Provider NOT provided … You passed model=…" — nothing usable was derived from the string. LiteLLMUnknownProvider at exceptions.py line 902 carries "Unmapped LLM provider for this endpoint. You passed model=…, custom_llm_provider=…" — a provider was derived, but there is no route for it on that endpoint. The second is what to expect when a provider works for one role and not another.
One conflict sends people to the wrong field. Agent Zero's FAQ says openai/gpt-5.3 is correct for OpenRouter but incorrect for the native OpenAI provider, "which goes without prefix", and the install guide's naming table lists OpenAI as "Model name only". Those describe the text box; the code prepends on top of it. Both are true once the layer is named. That table also carries a documentation bug — its OpenAI row uses an Anthropic model id as the example — so do not copy the cell.
Find out which of the three roles failed
Agent Zero configures three roles independently — chat, utility and embedding — each with its own provider, model name and API base. The settings sections are chat_model, utility_model and embedding_model, while the legacy flat keys are chat_model_*, util_model_* and embed_model_*; searching settings.json for the wrong convention finds nothing. There is a fourth, optional selection worth knowing about: the bundled browser plugin has its own model_preset, shipped empty and documented as "Empty uses the effective Main Model" — so unless you set it, a browser-tool failure is the chat role failing under another name. And one successful chat reply proves one role works, not three.
The embedding role differs in two ways that change triage. LiteLLMEmbeddingWrapper.embed calls LiteLLM's embedding() with no try/except and no attempt loop, so it raises on the first attempt regardless of class. And the shipped default is provider huggingface with the name sentence-transformers/all-MiniLM-L6-v2; models.py routes any huggingface name starting sentence-transformers/ to an in-process wrapper the code describes as avoiding HuggingFace API calls, so a fault there need not involve any network call.
Kunavo serves no embedding model, so the roles a Kunavo key can fill in Agent Zero are the chat and utility ones.
OpenRouter is the confirmed role split, and the one branch here with a maintainer fix rather than an inference. Issue #1597, "OpenRouter embedding models fail due to LiteLLM missing provider route", opened May 2, 2026 and closed August 27, 2026, hours before v2.11 shipped that same day. Two things need separating there, because they are easy to conflate. The config does route the provider by role — chat keeps native litellm_provider: openrouter, while embedding uses litellm_provider: openai plus an explicit api_base, under the maintainers' TODO that OpenRouter is "not yet supported by LiteLLM" — but that split reads identically on the v2.10 tag and on main, so it is not what closed the issue. The change that did is one line of models.py: on v2.10 the embedding wrapper built f"{provider}/{model}" if provider != "openai" else model, dropping the prefix on every openai-routed embedding, and from v2.11 it prefixes unconditionally, which is why the maintainer's closing note says ids containing a slash now reach the endpoint intact. On that branch the fix is the upgrade, not a settings change.
The key lookup, and why "change the key" often misses
get_api_key(service) reads three environment names in a fixed order and falls back to the literal string "None".
# Provider id `other` ("Other OpenAI compatible"). models.py reads these
# three names in this order and stops at the first non-empty value.
API_KEY_OTHER=sk-...
# OTHER_API_KEY=sk-...
# OTHER_API_TOKEN=sk-...
# A comma in the value is not a syntax error: models.py splits on it
# and rotates the resulting keys round-robin.That placeholder is filtered — the call site checks api_key not in ("None", "NA") before attaching it — so an unresolved key means no api_key argument is sent at all, and LiteLLM applies its own environment lookup instead. A 401 can arrive from a credential you never chose. A second lookup uses a different service value: _merge_provider_defaults reads the key under the original provider id, then _get_litellm_chat falls back to get_api_key(provider_name), by which point that name is the LiteLLM provider — openai, for other. So an unset API_KEY_OTHER alongside an OpenAI key in the same .env sends the OpenAI key to your endpoint. Read from those two functions on main; undocumented and not runtime tested here.
The install guide places the key under External Services → Other OpenAI-compatible API keys, then OpenAI Compatible as the provider. Two documented symptoms nearby are not model-id faults: when nothing happens on send, the FAQ blames keys not set in Settings; and ChatGPT Plus includes no API credits — though the bundled OAuth plugin ships a codex_oauth connection that signs in with an OpenAI account instead, so "no subscription can drive Agent Zero" would be wrong.
The endpoint, and two rules that look contradictory
The other provider ships no default api_base, and ModelConfig.build_kwargs forwards that field only when non-empty — so a blank API URL sends no base and LiteLLM's stock openai default applies. Which host that resolves to in 1.88.1 was not checked here; treat a 401 on a blank URL as a reason to fill the field, not a diagnosis. LiteLLM's compatible-endpoint page then carries two notes pulling opposite ways: "Do NOT add anything additional to the base url e.g. /v1/embedding" and "If you see Not Found Error when testing make sure your api_base has the /v1 postfix." They reconcile as one rule — end at /v1, add nothing after it.
Under Docker, the install guide is explicit that localhost and 127.0.0.1 in an API base URL mean the container: use http://host.docker.internal:<port>, or a gateway address such as http://172.17.0.1:<port> on the default Linux bridge, and move a server bound to host loopback onto something Docker-reachable such as 0.0.0.0. Then confirm the config you are reading is the one that ran: A0_SET_ presets are initial defaults only — "Once a value is saved in settings.json, it takes precedence over these environment variables" — with a restart required. Separately, issue #1769 (opened July 15, 2026, still open) reports LiteLLM calling exit(-9) when a model's registered provider differs from the one serving it: one reporter's analysis, unconfirmed and not reproduced here.
What the wrong fix costs
The quickest way to silence a failing utility role is to point it at the main model. It works, and it bills at the main model's rate for traffic the install guide describes as summarization and memory extraction. These figures are illustrative token arithmetic, not measured task costs and not a bill ceiling: assume a day of main-model work at 1200k input and 60k output tokens, utility traffic at 320k and 24k, and live Kunavo catalog rates per million tokens.
| Model in the utility slot | Input / output per 1M | Utility traffic, one day |
|---|---|---|
| Claude Sonnet 4.6 | $1.20 / $6.00 | $0.528 |
| GPT-5.6 Terra | $0.70 / $4.20 | $0.325 |
| Gemini 3.8 Flash | $0.525 / $2.625 | $0.231 |
| Claude Haiku 4.5 | $0.40 / $2.00 | $0.176 |
The main role itself models at $1.800 for that day; collapsing the utility role onto Claude Sonnet 4.6 adds $0.528 where Claude Haiku 4.5 models at $0.176. Mind the capability floor, though: the install guide warns that utility models must be "strong enough to extract and consolidate memory reliably" and that very small models, around 4B, usually fail at reliable context extraction. The guide describes that as failing at the task rather than as an error, so it is the branch where "the model errored" is the wrong diagnosis.
Agent Zero itself costs nothing to license — its LICENSE on main is MIT text, copyright "Agent Zero, s.r.o" — so the money is model tokens across the roles you configure. Kunavo's catalog amount is a billing floor, not a cap: when the upstream reports its charge, the bill is the greater of catalog cost and upstream cost times the applicable markup. The minimum top-up is $10 in prepaid credit. See billing details.
Which route to put behind the roles
| Route | Wins when | What it costs you in this failure mode |
|---|---|---|
| Direct vendor API | One vendor all day, on that vendor's own caching and batch terms | Each provider has its own entry and prefix, so a second vendor is a second set of names to get right |
| A named gateway (OpenRouter) | You switch models per task and want Agent Zero to route it natively | Native for chat only — the embedding entry routes through openai with an explicit base URL instead |
An OpenAI-compatible gateway via other | One key and one balance on an endpoint Agent Zero has no entry for | No model list to autocomplete from, no default base URL, and the key falls back to the OpenAI names if its own is unset |
| Account sign-in, via the OAuth plugin | You already pay for an account it connects — a Codex plan, GitHub Copilot — and would rather not paste a key | Its README says those connections take no API key from you at all — they connect an account, not an endpoint of yours; and its Google Cloud Gemini entry states it bills as the Gemini API rather than off a subscription |
| Local model server | Small or private work with no per-request charge | The Docker address rules apply, and the utility-role capability floor bites hardest here |
For per-role budgeting see Agent Zero API costs; for that third slot, changing the embedding model; for base-URL and prefix conventions generally, OpenAI-compatible API. Wiring a Kunavo key into other: start from the error reference, then create an account. Agent Zero has not been runtime tested against Kunavo's endpoint, so keep a working route available while you try it.
FAQ
Why does Agent Zero reject a model name that is spelled correctly?
Because Agent Zero does not send the name you typed. On agent0ai/agent-zero main, models.py builds f"{provider}/{model}" before every LiteLLM call — line 385 for the chat roles and line 800 for the embedding role — and the provider half is the litellm_provider value from conf/model_providers.yaml, not the label in the Settings dropdown. For the provider id `other` ("Other OpenAI compatible") that value is openai and _adjust_call_args remaps it again, so what LiteLLM receives is openai/<your-model>. Type the bare id with no prefix. Reading those two code sites, typing openai/gpt-4o yourself would produce openai/openai/gpt-4o — that consequence is inference from the code, not something observed or documented. Source read September 21, 2026.
Does a LiteLLM model error in Agent Zero mean my API key is wrong?
Not usually, and the status code separates them. In the litellm 1.88.1 wheel Agent Zero pins, an auth fault is AuthenticationError at 401, while the two provider-resolution faults are 400s: get_llm_provider_logic.py raises BadRequestError with "LLM Provider NOT provided", and LiteLLMUnknownProvider — a subclass of BadRequestError at exceptions.py line 902 — carries "Unmapped LLM provider for this endpoint". Both carry an integer status_code, and Agent Zero's _is_transient_litellm_error retries a status-carrying error only on 408, 429 and 5xx — so both classes surface on the first attempt and neither is evidence about the other. Check the model string and the base URL before rotating a key.
Why does only the embedding model fail in Agent Zero?
Because that role is routed and retried differently from the chat roles. LiteLLMEmbeddingWrapper.embed in models.py calls LiteLLM's embedding() with no try/except and no attempt loop, so it raises on the first attempt whatever the class, while the chat paths retry transient errors. The shipped default for the role is provider huggingface with the name sentence-transformers/all-MiniLM-L6-v2, and models.py routes any huggingface name starting sentence-transformers/ to an in-process wrapper the code describes as avoiding HuggingFace API calls — so a failure there need not involve a network call at all. OpenRouter is the documented split: conf/model_providers.yaml routes it natively for chat but as litellm_provider openai plus an explicit api_base for embedding, under a maintainer TODO. Kunavo serves no embedding model, so that slot goes to the local default or to a provider that sells that step.
Which LiteLLM version does Agent Zero use?
requirements.txt on agent0ai/agent-zero main pins litellm==1.88.1, with the inline comment "CVE-2026-42271 fix: patched floor is 1.83.7". PyPI records 1.88.1 as uploaded June 9, 2026, while the current release is 1.102.0, uploaded September 20, 2026. Behaviour, parameter support and error wording LiteLLM added after 1.88.1 are therefore not in an Agent Zero install, and checking a symptom against LiteLLM's current documentation can describe code you are not running. Checked September 21, 2026; a hand pip install inside the container can of course change the version.
Should I type a provider prefix in Agent Zero's Model Name field?
No, and Agent Zero's own documentation agrees about the field you fill in: its FAQ says openai/gpt-5.3 is correct for OpenRouter but incorrect for the native OpenAI provider, "which goes without prefix", and the install guide's naming table lists OpenAI as "Model name only". Those sentences describe the text box; the code then prepends the LiteLLM provider on top of whatever you typed. Both are true once you name the layer, and a sentence that blurs them is not. One caution on that table: its OpenAI row uses an Anthropic model id as the example, so it illustrates the format rather than showing a working OpenAI id.
Why did Agent Zero retry one error and not another?
When the exception carries an HTTP status, that status decides and nothing else does. _is_transient_litellm_error in models.py checks for an integer status_code first: true for 408, 429, 500, 502, 503 and 504, true for any other 5xx, false for every other status — so a 400 or a 401 is final however serious it looks. Only when no status code is present does it fall back to matching exception classes, timeouts and connection errors among them, which is why a failure with no HTTP status can still be retried. A second gate trips people up: models.py line 638 raises instead of retrying when got_any_chunk is true, so a transient error landing after streaming has started is not retried either. "It failed at once" is not by itself proof that the error was a 400 or a 401.
Agent Zero behaviour read from source on the agent0ai/agent-zero main branch — models.py and conf/model_providers.yaml — plus its docs, releases and issues, on September 21, 2026; LiteLLM exception classes and error strings read inside the litellm 1.88.1 wheel from PyPI, the version Agent Zero pins. Nothing here was runtime tested: no install was run and no error reproduced end to end. Kunavo token rates come from the live catalog, and every dollar figure is illustrative token arithmetic.