Model retirement is not an accident: turning deprecation into a scheduled task
A typical morning
07:40. Monitoring fires: the core endpoint is returning 500. One line in the log:
{"error":{"message":"model_not_found","type":"invalid_request_error"}}
It worked yesterday. You did not change the code, upgrade the SDK or rotate the key. The only thing that changed is that the upstream retired that model.
This happens several times a year in every team, and it never needs to happen at all — because a retirement is never a surprise. The vendor publishes a notice ahead of time, the relay receives it, and nobody turns it into a ticket in your backlog.
Retirement propagates through three layers
Layer one: vendor deprecation
Major vendors give notice: Anthropic, OpenAI and Google usually maintain a deprecations page with three to twelve months of lead time. Chinese vendors tend to be shorter, commonly one to three months.
The defining feature of this layer: the information is public, but you will not go looking for it.
Layer two: the relay removes the route
Once the vendor retires a model, the entry disappears from the relay's model list. The problem is that three common behaviours differ enormously:
- Some announce it in advance, some simply vanish;
- Some keep the old model name and silently forward to the new model — good for you, except you do not know the output changed;
- Some keep the name and return 404 without telling you what replaced it.
Which of these three you get decides whether your code breaks.
Layer three: the model name hardcoded in your code
resp = client.chat.completions.create(model="claude-sonnet-5", ...)
This line is the last line of defence, and the only layer you fully control.
Inventory your own model names first
Before discussing migration, answer a basic question: how many model names does your project contain, and in which files?
# adjust the pattern to your naming convention
grep -rhoE '"(gpt|claude|gemini|qwen|glm|kimi|deepseek|grok|doubao)[a-zA-Z0-9._-]*"' \
--include=*.py --include=*.ts --include=*.js --include=*.go . \
| sort | uniq -c | sort -rn
You will usually get a longer list than expected — test files, comments, CI configuration, and a script left behind by someone who has since left the team.
Then give every entry four fields:
| Current name | Used for | Replacement | Latest switch date | Status |
|---|---|---|---|---|
| claude-sonnet-5 | main chat | claude-sonnet-5.5 | 2027-03-01 | evaluating |
| gpt-5.6-luna | summaries | gpt-5.6-luna-2 | 2026-12-15 | switched |
This table needs no tooling; a Markdown file is enough. Its value is not that it looks tidy, but that next time you get a 404 you have something to look up.
Four questions for the relay
- Will you notify before retirement, and through which channel? Email, site notice, API, or not at all.
- How long does the old name survive? Immediate 404, or forwarding to the replacement for a while.
- Do you offer aliases? Names like
claude-sonnet-latestwithout a minor version. With an alias you do not touch code when the vendor moves a minor version. - Can I still query historical usage afterwards? Needed for reconciliation and cost retrospection.
Question three has the best return. An alias removes most of the migration work — provided you verify it really follows upstream instead of pointing at one frozen version. The test is easy: record the model identifier the alias currently reports (most APIs include a model field in the response), check again two weeks later, and if it changed, it is following.
Migration is not a rename
This is the most underestimated step. After switching models, six things can change:
| What changes | How it shows up | How to check |
|---|---|---|
| Output format | New thinking or reasoning fields, different tool-call structure | Run a fixed test set and diff the structure |
max_tokens ceiling | Lower on the new model, long output truncated | Request one very long output and read finish_reason |
| Context length | Shorter on the new model, long documents return 400 | Run your longest real input once |
| Price | Unit price moves, the bill may double | Compare with the official list and cost one typical request |
| Latency | The new model is slower, timeouts need retuning | Single-worker P95 |
| Refusal tendency | Safety policy changed, prompts that used to pass are rejected | Run real production samples |
Of these six, only price and latency are caught by ordinary monitoring. The other four surface slowly as "occasional failures" and "shorter output" unless you test for them.
Shadow rollout: spread the risk over a week
Do not switch everything at once. A workable order:
- Shadow mode: send the same inputs to the new model and only record the results. Run three days and compare divergence.
- Small traffic: route 5% to the new model, watch error rate and latency.
- Switch by scenario: low-risk surfaces first (summaries, classification), core chat last.
- Keep a rollback switch: the model name must be configurable, never hardcoded. This is the precondition for everything above.
How to compute divergence in step 1: take 200 real inputs, run both models, and manually review 20 pairs. Do not switch above a 15% divergence rate — first establish whether the difference is "better" or "off target".
Summary
- A retirement is not an outage; it is a notice nobody turned into a ticket.
- It propagates through vendor, relay and your code, and any layer without a plan breaks.
- Inventory the model names in your code into a table with a latest-switch date.
- Prefer aliases, but verify they really track upstream instead of being pinned.
- Six things need checking in a migration; ordinary monitoring covers two.
- The minimum viable rollout is three days of shadow mode plus 5% traffic, with a rollback switch as the precondition.
Was this useful? If you have run into something the article does not cover, tell us and we will verify it and update the text.
Related articles
RPM, TPM and concurrency: the four real shapes of relay rate limiting, and how to find the true ceiling
Three traps in choosing a site from a leaderboard alone
Evening peak jitter: upstream, network path, or your own concurrency
Four ways to check a "direct official connection" or "pure resale" claim
A 30-minute emergency checklist after an API key leak
Five terms to check before topping up: balance, refunds and expiry, question by question
Read on: a few of the services we list
This article does not point at a specific model family, so here are a few of the highest-scoring services we list, in case you want to read on. They are ordered by score and uptime and are not a recommendation.
See the full list in the directory, or browse by model family.