If your app started throwing 404s on Friday, 23 October, check the model name before you check anything else.
That day OpenAI switched off a long list of older models: gpt-3.5-turbo, gpt-4, gpt-4-turbo, o1, o1-pro, o3-mini, o4-mini, gpt-4.1-nano, the May 2024 snapshot of gpt-4o, and gpt-image-1. Fine-tuned versions of those models went with them.
None of this was secret. OpenAI posted the notice on 22 April. But six months is plenty of time to forget about a model ID sitting in a cron job, and judging by the forum threads, a lot of people did.
This post covers what replaced each model, how to find every place you still call one, what the switch does to your bill (for some of you it goes up), and the settings that break a second time after the rename.
What the error looks like
A request to a retired model comes back as HTTP 404 with a body like this:
{
"error": {
"message": "The model `o4-mini` does not exist or you do not have access to it.",
"type": "invalid_request_error",
"param": null,
"code": "model_not_found"
}
}
The annoying part: OpenAI uses the same model_not_found code for a retired model, a typo in the model ID, and a model your organization isn't allowed to use. So before you dig through billing or permissions, look at the model name in the failing request. If it's in the table below, you've found your problem.
The status code helps tell the cases apart. A retired or misspelled model returns a 404. Developers who run into a project's model allowlist report a 403 with the same model_not_found code and a message along the lines of "Project ... does not have access to model ...". That model exists, and a project admin has to allow it.
OpenAI's error guide doesn't publish the exact wording of these messages, so branch on the status and the code field in your code, not on the text.
Every retired model and its replacement
This comes straight from OpenAI's deprecations page. Prices are OpenAI's list prices per million tokens, input / output, from its pricing page.
| Retired model | OpenAI's replacement | Old price | New price |
|---|---|---|---|
| gpt-3.5-turbo | gpt-5.6-terra | $0.50 / $1.50 | $2.00 / $12.00 |
| gpt-4 | gpt-5.6-sol | $30.00 / $60.00 | $4.00 / $20.00 |
| gpt-4-turbo, gpt-4-1106-preview | gpt-5.6-sol | $10.00 / $30.00 | $4.00 / $20.00 |
| gpt-4o-2024-05-13 | gpt-5.6-sol | $5.00 / $15.00 | $4.00 / $20.00 |
| gpt-4.1-nano | gpt-5.6-luna | $0.10 / $0.40 | $0.20 / $1.20 |
| o1 | gpt-5.6-sol | $15.00 / $60.00 | $4.00 / $20.00 |
| o1-pro | gpt-5.6-sol, with reasoning.mode: pro | $150.00 / $600.00 | $4.00 / $20.00 |
| o3-mini | gpt-5.6-sol | $1.10 / $4.40 | $4.00 / $20.00 |
| o4-mini | gpt-5.6-terra | $1.10 / $4.40 | $2.00 / $12.00 |
| gpt-image-1 | gpt-image-2.5-sunburst or gpt-image-2.5-flare | not listed | $5 text in, $8 image in, $30 image out |
A few details that cause confusion:
- The dated snapshots went too, so
o4-mini-2025-04-16andgpt-4-0613are gone along with their short names. - Only the May 2024 gpt-4o snapshot was retired. Plain
gpt-4oand its later snapshots keep working until 14 January 2027. - The gpt-5.6-sol price is a promotion. OpenAI says it runs "at least through November 21, 2026", so plan for it changing.
- o1-pro has no separate Pro model now. You keep gpt-5.6-sol and set
reasoning.modetopro, which only works in the Responses API. Pro mode is billed at Sol's normal token rates, but it does more work per answer, so expect more tokens per request.
If you haven't looked at the GPT-5.6 family yet, OpenAI's own introduction is short:
Some of you just got a price increase

If you were on gpt-4, gpt-4-turbo or o1, good news. Moving gpt-4 traffic to gpt-5.6-sol cuts input cost from $30 to $4 per million tokens.
The small models go the other way. gpt-4.1-nano to gpt-5.6-luna doubles the input price and triples the output price. o4-mini to gpt-5.6-terra nearly triples output. And anyone still running gpt-3.5-turbo is looking at 8x more per output token on terra.
The replacements OpenAI names aren't your only option, and they aren't the lowest-priced ones either. Its newer models undercut them:

| Instead of | Try | Price |
|---|---|---|
| gpt-5.6-terra ($2 / $12) | gpt-6.1-terra | $1.00 / $5.00 |
| gpt-5.6-sol ($4 / $20) | gpt-6.1-sol | $2.00 / $10.00 |
| gpt-5.6-luna ($0.20 / $1.20) | gpt-6-luna | $0.10 / $0.50 |
Check two things before you switch. The 6.1 models only do tool calling through the Responses API, not Chat Completions. And gpt-6.1-sol doesn't accept a reasoning effort of none. If your old code calls functions through Chat Completions, gpt-6-luna or the 5.6 family is the shorter move. And if the work can wait up to a day, the Batch API halves all of these prices.
Whichever you pick, don't just paste in a model name and move on. Run a few hundred of your real prompts through two candidates and compare. A lower price doesn't help if the model gets 2% more answers wrong. That can still cost you more.
Find every place that still calls a retired model
Renaming is quick. Finding every caller is the slow part.
Start with the API. The List models endpoint now returns a shutdown_date for any model that has one, so this prints every model your key can reach that has a date set, soonest first:
curl -s https://api.openai.com/v1/models \
-H "Authorization: Bearer $OPENAI_API_KEY" \
| jq -r '.data[] | select(.shutdown_date) | "\(.shutdown_date) \(.id)"' | sort
Then find the callers. The Usage API breaks token use down by model and by API key, so you can see which key, and so which service, was calling o4-mini or gpt-4.1-nano. It needs an admin key. This asks for daily totals from 1 October (1790812800 in Unix time), the weeks when those models were still in use:
curl "https://api.openai.com/v1/organization/usage/completions?start_time=1790812800&bucket_width=1d&limit=31&group_by=model&group_by=api_key_id" \
-H "Authorization: Bearer $OPENAI_ADMIN_KEY"
Then check the places a code search misses:
- Batch input files. Each file can only contain requests to one model, so a batch job built for gpt-3.5-turbo needs a regenerated input file, not just a new job.
- Saved prompts. A request can pass a saved prompt ID (
pmpt_...) with no model in your code at all, because the model is stored with the prompt in the dashboard. Thev1/promptsAPI itself shuts down on 30 November 2026, so move that prompt text into your code while you're there. - Env files, scheduled jobs, eval scripts, framework defaults, and the notebook a teammate runs on Mondays.
The fix
Mostly, you change the model name:
from openai import OpenAI
client = OpenAI()
response = client.chat.completions.create(
model="gpt-5.6-terra", # was "o4-mini", which now returns 404
messages=[{"role": "user", "content": "Summarize this support ticket in one line."}],
)
print(response.choices[0].message.content)
What else changes when you switch
The new models aren't copies of the old ones with new names. Four differences cause most of the second round of errors:
- GPT-5.6 models reason before they answer, and if you don't set a reasoning effort, they use
medium. gpt-3.5-turbo, gpt-4 and gpt-4.1-nano had no reasoning step, so a straight swap makes simple calls slower and adds reasoning tokens to the bill. For classification, extraction or short replies, start atnoneorlowand raise it only if quality needs it. max_tokensis deprecated in favor ofmax_completion_tokens, and the new limit counts reasoning tokens too. A tight limit that suited gpt-3.5-turbo can run out during reasoning, before any visible text is produced. You pay for the reasoning and get an empty answer.- OpenAI recommends the Responses API for reasoning, tool calling and multi-turn work on GPT-5.6. On gpt-6-luna and gpt-6-sol, function calling through Chat Completions only works with
reasoning_effort: "none". - On the GPT-6 models, OpenAI says to remove
temperature,top_pandtop_logprobswhenever reasoning effort isn'tnone.
For a simple task moving off gpt-3.5-turbo, that looks like this:
response = client.chat.completions.create(
model="gpt-5.6-terra",
reasoning_effort="none", # GPT-5.6 defaults to "medium"
max_completion_tokens=300, # replaces max_tokens, and includes reasoning tokens
messages=[{"role": "user", "content": "Classify this ticket as billing, bug or feature request: ..."}],
)
If you rely on prompt caching, check those numbers too. Writing to the cache on GPT-5.6 costs 1.25x the normal input rate, so watch cached_tokens and cache_write_tokens in the usage data to see what you actually save.
For a longer walk through choosing between Sol, Terra and Luna, and moving tool schemas and caching across, OpenAI's Build Hour on GPT-5.6 is worth the time. It was recorded in July, so check any prices in it against the pricing page.
Add a fallback while you're in there
A tested fallback turns the next shutdown into a log line instead of an outage. The OpenAI SDK retries timeouts, rate limits and server errors on its own, but not a 404 or a 403, so catch those yourself:
import logging
from openai import OpenAI, NotFoundError, PermissionDeniedError
client = OpenAI()
MODELS = ["gpt-5.6-terra", "gpt-6-luna"] # first choice, then a fallback you've tested
def complete(messages):
for model in MODELS:
try:
return client.chat.completions.create(model=model, messages=messages)
except (NotFoundError, PermissionDeniedError) as e:
if e.code != "model_not_found":
raise
logging.warning("%s is unavailable, trying the next model", model)
raise RuntimeError("no model in MODELS is available")
Pick the fallback with the calendar in mind. gpt-5, gpt-5-mini, gpt-5-nano, gpt-5-pro, o3 and o3-pro all shut down on 11 December, so none of them is a safe choice.
Fine-tuned models
A fine-tune of a retired model is retired with it, and training a new one isn't the easy way out it used to be. OpenAI is winding down its fine-tuning platform. It's closed to new users, and existing customers can create training jobs until 6 January 2027, or until the base model shuts down if that's earlier. For most teams the practical replacement is a current model with a handful of good examples in the prompt, checked against the old fine-tune's outputs.
On Azure? Different dates, different error
Azure OpenAI runs its own schedule, so OpenAI's list doesn't apply directly. When an Azure model version retires, requests return 410 Gone instead of a 404. The dates differ too:
- o1, o1-pro, o3-mini and o4-mini retire on Azure on 19 November 2026, almost a month after OpenAI.
- gpt-4o version 2024-05-13 retires on 14 January 2027. Global Standard and Data Zone Standard deployments of it upgrade automatically to gpt-5.1 (2025-11-13), not to a GPT-5.6 model.
- gpt-4.1-nano stays on Azure until 14 April 2027.
Check Microsoft's retirement schedule, not OpenAI's.
The next shutdowns
More are coming. OpenAI's policy promises at least six months' notice for generally available models, but don't plan around that. The 14 January shutdown of gpt-4o and gpt-4.1 was announced on 14 October, three months ahead.

| Date | Shutting down | OpenAI's replacement |
|---|---|---|
| 30 Nov 2026 | v1/prompts API and saved prompt objects | Prompt text in your own code |
| 1 Dec 2026 | gpt-image-1.5, gpt-image-1-mini, chatgpt-image-latest | gpt-image-2.5-sunburst or gpt-image-2.5-flare |
| 11 Dec 2026 | gpt-5, gpt-5-mini, gpt-5-nano, gpt-5-pro, o3, o3-pro | gpt-5.6-sol, terra or luna |
| 6 Jan 2027 | tts-1, tts-1-hd, gpt-4o-mini-tts | gpt-realtime-2.1-mini |
| 14 Jan 2027 | gpt-4o, gpt-4o-mini, gpt-4.1, gpt-4.1-mini | gpt-6-luna |
| 26 Feb 2027 | whisper-1, gpt-4o-transcribe, gpt-4o-mini-transcribe | gpt-live-transcribe or gpt-transcribe |
| 1 Apr 2027 | gpt-5.1, gpt-5.3-codex, gpt-5.4-nano | gpt-6-sol, or gpt-6-luna for nano |
Three things worth doing now, while it's still quiet:
- Keep model IDs in config, not in code. One setting per job means one change per migration.
- Give every job a fallback model that you've actually tested, like the snippet above.
- Run the
shutdown_datecheck from earlier once a week in CI, and alert when a model you call gets a date. That beats remembering to read the deprecations page.
Where Aight fits
Aight is one OpenAI-compatible API for 126 models from OpenAI, Anthropic, Google, xAI, DeepSeek and others. The text replacements above (gpt-5.6-luna, gpt-5.6-terra, gpt-5.6-sol), plus gpt-6-luna and gpt-6.1-sol, are on it at OpenAI's list prices, so you can test them side by side with Claude or Gemini on the same key.
If you already use the OpenAI SDK, switching is two lines:
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.getaight.ai/v1",
api_key=os.environ["AIGHT_API_KEY"],
)
A few things that help in a week like this one:
- Each key can have a list of allowed models. A forgotten script can't quietly call something you didn't plan for, because anything outside the list gets a 403.
- Aight gives at least 14 days' notice before it removes a model, where the provider allows, and names a replacement.
- Balance is prepaid in US dollars and doesn't expire. Recharges start at $5 plus a 3% processing fee, and every recharge adds 10% extra balance.
The quickstart covers sign-up to first request in four steps.
One last thing. If you've switched the model and still see 404s, search for the old name again. It's nearly always hiding in one more place.
Sources
- OpenAI, Deprecations: the 23 October shutdowns, replacements, upcoming dates, the
shutdown_datefield and the notice policy - OpenAI, Pricing: current, legacy and Batch prices
- OpenAI, Upgrading to GPT-5.6 and Reasoning models: default reasoning effort, pro mode, tool calling, unsupported parameters, empty responses
- OpenAI, Usage API: completions, Batch API, Migrate from prompt objects, Supervised fine-tuning
- OpenAI, Error codes and the openai-python README (which errors the SDK retries)
- OpenAI developer forum, [a 403
model_not_foundfrom a project allowlist](https://community.openai.com/t/project-does-not-have-access-to-model-gpt-5-2-403-model-not-found-error/1371814) - Microsoft, Azure OpenAI model retirement schedule
- Aight, Models and pricing and API reference
Prices and dates checked on 31 October 2026.