# When a provider retires a model: a migration playbook

URL: https://infro.io/blog/model-deprecation-migration-playbook
Author: INFRO Editorial (https://infro.io/blog/editorial)
Publisher: INFRO
Published: 2026-09-29
Last modified: 2026-09-29
Last reviewed: 2026-09-29 (next review due 2026-10-29)
Topic: Evaluation and models
Format: Guide

> When a provider deprecates a model, find every caller from your own request data, test the named replacement on recorded tasks including the parameters it now refuses, put the model behind a route, move traffic by weight while comparing errors, length and cost per task, block the old id, and watch the served model after cut-over.

Key takeaways:
- Deprecation notice periods range from two weeks for OpenAI previews to at least six months for its generally available models; Google's listed dates are the earliest possible shutdown.
- Retirements break more than model ids: parameters change too, as Anthropic's 400 on non-default temperature for newer models shows.
- Find callers from request data by model and key, not from a code search; configuration, fallbacks and forgotten jobs hide from grep.
- Put the model behind a route, then move traffic by weight in saved steps, comparing errors, truncation, output length and cost per successful task.
- After cut-over, watch which model actually served. Aliases and snapshots can change the model behind a name without an error.

On 24 September 2026, OpenAI's Videos API stopped answering. The deprecations page records the announcement on 24 March — `sora-2`, `sora-2-pro`, every variant and the API itself — with no replacement listed[1]. Six months is a generous notice period. It is still six months in which every team that built on Sora had to find a different vendor, a different job API and a different set of prompts that work.

Most retirements are smaller: one model, a named successor, a date. They still fail the same way when nobody acts. Anthropic says it plainly: requests to models past the retirement date will fail[2]. This guide is the playbook for the months between the email and the date.

## How the three largest vendors retire models

The vocabulary differs, and so do the promises.

**OpenAI** separates *deprecation*, the announcement, from *shutdown*, when the model is no longer accessible, and calls models that no longer receive updates *legacy*. It notifies customers by email and in its documentation, and gives at least six months' notice for generally available models, at least three months for specialized variants, and as little as two weeks for preview models[1].

**Anthropic** moves models through *active*, *legacy*, *deprecated* and *retired*, notifies customers with active deployments, and gives at least 60 days' notice before retiring a publicly released model. Its dates apply to Anthropic-operated platforms; Amazon Bedrock and Google Cloud set their own schedules. It also offers a usage export by API key and model to find what still calls a deprecated model[2].

**Google** defines a deprecation as the announcement that a model will be shut down, and says the shutdown dates in its table are the *earliest possible* dates, with notice given before the exact date[3].

[Diagram: Minimum notice by published policy. Google's table gives earliest possible shutdown dates rather than a fixed notice period, so it is not charted. INFRO's catalog notice is its own policy for catalog entries; your provider's date still governs whether the model answers.]

## What retired this year

[Diagram: Retirements and scheduled shutdowns across OpenAI, Anthropic and Google, from each vendor's deprecation page, read 2026-09-29.]

Anthropic retired Claude Sonnet 4 and Opus 4 on 15 June 2026 and Opus 4.1 on 5 August[2]. Google's table lists Veo 3.0 for 30 June, Imagen 4 for 17 August and `gemini-2.5-flash-image` for 2 October[3], and its Imagen page now says the models are shut down[4]. OpenAI shut down the Videos API on 24 September and has scheduled `gpt-image-1.5` and `gpt-image-1-mini` for 1 December and `whisper-1` with the `gpt-4o` transcription models for 26 February 2027[1]. The Sora 2 model page now reads as discontinued[5].

If you use several vendors, that is a retirement to manage most months.

## What actually breaks

The model id is the obvious failure. Three less obvious ones cause most migration incidents:

- **Parameters.** Anthropic has deprecated `temperature`, `top_p` and `top_k` for Claude Opus 4.7 and later: a non-default value returns a 400, and its Python SDK from v1.0 removes the parameters so passing them raises a `TypeError`[2]. Code that always sends `temperature: 0` breaks on the replacement, not on the retiring model.
- **Behaviour.** Output length, formatting, refusals, tool-call patterns and structured-output support shift between versions. Nothing errors; downstream parsers and budgets notice first.
- **Whole APIs.** When the Videos API went, the job protocol went with it[1]. Any replacement had a different request shape, not just a new model name.

## The playbook

[Diagram: Six steps from notice to cut-over. Most of the risk sits in the first two.]

### 1. Inventory from traffic, not from code

A code search misses model ids in configuration, environment variables, fallback lists, notebooks and scheduled jobs. Start from what was actually sent: requests by model, by API key and by project over the last 30 days. Anthropic's usage export does this per key for its own API[2]; a gateway's request log does it across every provider. Then keep a register of every model you use with its vendor status and date, and check it automatically.

```python
"""Fail CI when configured models are near or past a vendor retirement date."""
import datetime as dt
import json
import sys

# Maintained by hand from the vendors' deprecation pages; review monthly.
REGISTER = {
    "claude-opus-4-1-20250805": {"retires": "2026-08-05", "replacement": "claude-opus-4-8"},
    "gpt-image-1.5": {"retires": "2026-12-01", "replacement": "gpt-image-2.5-sunburst"},
    "whisper-1": {"retires": "2027-02-26", "replacement": "gpt-transcribe"},
}
WARN_DAYS = 60


def check(config_path: str, today: dt.date) -> int:
    with open(config_path) as f:
        models = set(json.load(f)["models"])  # every model id your services may call
    failures = 0
    for model in sorted(models & REGISTER.keys()):
        entry = REGISTER[model]
        days_left = (dt.date.fromisoformat(entry["retires"]) - today).days
        if days_left <= 0:
            print(f"ERROR {model} retired {-days_left} days ago -> {entry['replacement']}")
            failures += 1
        elif days_left <= WARN_DAYS:
            print(f"WARN  {model} retires in {days_left} days -> {entry['replacement']}")
    return failures


if __name__ == "__main__":
    sys.exit(1 if check(sys.argv[1], dt.date.today()) else 0)
```

### 2. Qualify the replacement on recorded work

Take the vendor's recommended replacement as the first candidate, not the only one. Run it on a few hundred recorded requests from each workload the inventory found, with the exact request shape your code sends, including sampling parameters and tools. Compare task success, refusals, output tokens and truncation, and compute cost per successful task at your provider's rate. A replacement with a higher list rate can cost less per task if it needs fewer retries; one with a lower list rate can cost more if its answers run longer.

### 3. Put the model behind a name you control

If services call a vendor model id directly, every retirement is a multi-repository change. Point them at a route or alias you own, so the model becomes configuration. Do this before the migration, not during it.

### 4. Move traffic by weight

[Diagram: An illustrative weighted migration on one route. Each stage is one saved edit, and the replacement starts as a zero-weight standby.]

Hold each stage long enough to see the rarer paths — tool calls, long inputs, the weekly batch job — and compare the replacement against the old model on the same metrics you used to qualify it. Keep the retiring model off the route's fallback list once you are past the first stage: a fallback to a model that is about to disappear protects nothing.

### 5. Close the door on the old id

Before the shutdown date, stop new code from calling the retiring model at all. An allowlist that no longer includes it turns a future outage into an immediate, explicit refusal that shows up in development.

### 6. Watch what serves after cut-over

For two weeks after the switch, watch output tokens per request, truncation, refusals, fallback rate and estimated cost, and read the model id the provider reports on each response. Aliases and snapshots mean the name you send is not always the model that answers.

```typescript
// Log when the model that served differs from the one this service was qualified on.
const QUALIFIED = new Set(["anthropic/claude-sonnet-5.5"]);

export function checkServedModel(response: { id: string; model: string }, route: string) {
  if (!QUALIFIED.has(response.model)) {
    console.warn(JSON.stringify({ event: "unqualified_model_served", route, served: response.model, request: response.id }));
  }
}
```

## Running a migration with INFRO routes

In INFRO the application calls a [route](https://infro.io/docs/routes) — `support-agent`, `nightly-summary` — that resolves to an ordered list of targets, each a model and one of your own provider connections. A `weighted` route picks the first target in proportion to its weight and falls through the rest if it fails; a target at weight 0 is a standby that never takes a first attempt. Targets are saved as a whole list in one write, so production never passes through an intermediate state with two primaries or none. That is the canary above, done in the console with no deploy.

A route may not reach a model your [model allowlist](https://infro.io/docs/org/model-allowlists) forbids: the target is skipped, and a direct call to a disallowed model is refused with `403 model_not_allowed` before any provider is called. Removing the retiring model from the allowlist is step 5. An API key can also be pinned to named routes, so it cannot call a model id directly at all.

For the inventory, the request log records the model, provider, connection and key of every request, and each row carries `served_model` — the model id your provider's reply named — which `GET /v1/requests` filters on. [Traffic changes](https://infro.io/docs/observability/traffic-changes) raise a `traffic.model_changed` finding when a model on one connection starts being answered by an id that connection had not reported in the previous 14 days, with output tokens, truncation and estimated provider cost before and after. It reads metadata only, so it tells you that the served model changed and what it costs, not whether answers got worse.

INFRO's own catalog has a lifecycle too. Catalog entries are deprecated with at least 30 days' notice, announced by email and in the console, and a retired catalog id becomes an alias for its designated successor, so old code does not start returning 404 from INFRO. That alias is a catalog convenience, not a migration: the request is then served and estimated as the successor, which your connections must serve and which you have not necessarily evaluated. The response `model` field always reports the model that served; log it. See [models](https://infro.io/docs/models). Whether a model answers at all is decided by the provider whose account you connect.

## Questions

### Do Bedrock and Vertex AI retire Claude models on the same dates as Anthropic?

Not necessarily. Anthropic's deprecation page says its dates apply to Anthropic-operated platforms and that Amazon Bedrock and Google Cloud set their own retirement schedules, so check each platform's own model table.

### Should I pin a dated model snapshot or use the alias?

Pin a dated snapshot in production so behaviour changes only when you change it, and use the alias in development to see what is coming. Either way, record the model id the provider reports on each response.

## Sources

1. Deprecations — OpenAI. https://developers.openai.com/api/docs/deprecations (accessed 2026-09-29)
2. Model deprecations — Anthropic. https://platform.claude.com/docs/en/about-claude/model-deprecations (accessed 2026-09-29)
3. Gemini deprecations — Google. https://ai.google.dev/gemini-api/docs/deprecations (accessed 2026-09-29)
4. Imagen — Google. https://ai.google.dev/gemini-api/docs/imagen (accessed 2026-09-29)
5. Sora 2 model page — OpenAI. https://developers.openai.com/api/docs/models/sora-2 (accessed 2026-09-29)
