Model ids are not portable: api.anthropic.com wants dated ids, Gemini wants its own version strings, and every gateway defines slugs. A 404 here means "this host has no model by that exact string" — the fix is always to ask the endpoint what it serves.
The error
{
"error": {
"type": "model_not_found",
"message": "The model 'claude-sonnet' does not exist or you do not have access to it.",
"code": "model_not_found"
}
}Causes and fixes at a glance
| Cause | Fix |
|---|---|
| Model id from a different host | Each API has its own namespace — copy ids from the endpoint's own model list, not from blog posts. |
| Deprecated/renamed version | Providers retire dated snapshots; pin to a current id and subscribe to deprecation notes. |
| Typo'd or truncated slug | claude-sonnet isn't a model anywhere; exact strings matter. |
| Model exists but is disabled for your key/plan | Some hosts gate models by plan — the list endpoint shows what YOUR key can call. |
List models from the endpoint you're calling
GET /v1/models is the ground truth on any OpenAI-compatible host — it returns exactly the ids your key can use:
curl -s https://api.kunavo.com/v1/models \
-H "Authorization: Bearer $KUNAVO_API_KEY" \
| python3 -c "import json,sys; print('\n'.join(m['id'] for m in json.load(sys.stdin)['data']))"Resolve models at runtime, not hardcoded
Catalogs move (new snapshots, retirements). Resolve the model list at startup, prefer configured slugs with a fallback, and alert when a configured slug disappears from /v1/models instead of 404ing in production.
If you're calling through Kunavo
Kunavo uses stable human-readable slugs (claude-sonnet-4-6, gemini-2-5-flash, claude-fable-5) listed at GET /v1/models with per-model metadata, and retired slugs 301 to their successors on the site's model pages so links don't rot. The list endpoint is authoritative — llms.txt says the same to any agent reading it.
FAQ
Why does the same model id work on one API and 404 on another?
Because ids are namespaced per host: Anthropic's dated ids, Gemini's versioned names and each gateway's slugs are all different strings for related models. Always copy from the target endpoint's own model list.
How do I future-proof against model retirement?
Resolve /v1/models at startup, keep the model id in config (not code), define a fallback chain, and page yourself when a configured id vanishes — that turns a production 404 into a config change.
More error semantics live in the error reference; getting a key takes a minute via sign up and the authentication docs.