Azure OpenAI gpt-4 preview deprecated — 404 on retired model version
Preview model versions are always temporary. Missing the retirement date leads to a hard cutover during production — this page tells you exactly which versions retire when and how to migrate safely.
Quick fix (TL;DR)
gpt-4-1106-preview, gpt-4-0125-preview, gpt-4-vision-preview) have hard retirement dates. After retirement, deployments still exist in the portal but return 404 or degrade to an unpredictable substitute. Fix by (a) auditing all deployments for preview versions, (b) mapping to current GA versions, (c) redeploying with the GA version and updating client code, and (d) subscribing to the Azure OpenAI model retirements RSS feed for future notice.Real error messages you'll see
These are the exact strings returned by the Azure OpenAI service and its SDKs when this error occurs. Copy-paste-searching any of them should land on this page.
openai.NotFoundError: Error code: 404 - {'error': {'code': 'DeploymentNotFound', 'message': 'The API deployment for this resource does not exist.'}}HTTP/1.1 200 OK x-ms-deployment-model-substituted: true x-ms-original-model: gpt-4-1106-preview x-ms-substituted-model: gpt-4o-2024-08-06 (response may differ in behaviour — quality, format, JSON adherence)
HTTP/1.1 200 OK x-ms-model-deprecation-notice: "This model version will be retired on 2026-04-02. Migrate to gpt-4o-2024-08-06." x-ms-model-retirement-date: 2026-04-02
Reference
Deprecated / retired preview versions and their GA successors
| Retired version | Retirement date (approx.) | Recommended GA replacement | Migration notes |
|---|---|---|---|
| gpt-4-vision-preview | Aug 2024 | gpt-4o (multimodal) | Same message format, higher quality, cheaper |
| gpt-4-1106-preview | Apr 2025 | gpt-4o (2024-08-06) | JSON mode enum values differ slightly |
| gpt-4-0125-preview | Apr 2025 | gpt-4o (2024-08-06) | Function calling — parallel tools now on by default |
| gpt-4-turbo-2024-04-09 | Mid 2025 | gpt-4o (2024-08-06) | Same tool-use JSON schema, better throughput |
| gpt-35-turbo-1106 | Q2 2025 | gpt-4o-mini or gpt-35-turbo-0125 | gpt-4o-mini is smarter and cheaper |
| gpt-35-turbo-instruct | 2026 (announced) | gpt-4o-mini with system prompt | Instruct format → chat format migration required |
The four-stage model lifecycle on Azure
| Stage | What it means | Duration | Client behaviour |
|---|---|---|---|
Preview | Early access — may change or be removed without full notice | Weeks to months | Expect churn — do not build critical paths |
GA (General Availability) | Stable, versioned, supported | 12+ months typical | Safe for production |
Deprecated | End-of-life announced; still functional | 90+ days announced | Header warnings; plan migration |
Retired | No longer callable | Permanent | 404 or auto-substitution |
Root causes, ranked by frequency
Based on developer reports across Azure OpenAI SDK forums, GitHub issues, and Microsoft Q&A during 2025–2026.
- 40%Preview version used in production. Team deployed
gpt-4-1106-previewin 2024, put it in production, and did not track the retirement announcement. - 18%Deprecation email missed. Notification goes to the Azure subscription notification address, which is often a shared inbox that no engineer monitors.
- 12%Deployment shows "active" in the portal after retirement — the object still exists, but calls return 404. Portal state is a lagging indicator.
- 10%Third-party dependency pinned to a preview. A vendor library or gateway config still targets the old preview model.
- 8%Auto-substitution enabled but behaviour changed. Azure now silently substitutes retired models with a newer GA — code that expected specific formatting or JSON quirks breaks.
- 6%Multi-region deployment retired asynchronously. West Europe retires the model 1 week before East US, causing an intermittent outage that appears to be a regional issue.
- 4%Custom fine-tunes on preview base models. Fine-tunes retire when the base model retires — 60-90 days notice is typical.
- 2%API version incompatibility. The successor model requires a newer
api_version; upgrading the model without upgrading the api-version can surface as 400 errors.
Fixes — copy-paste solutions
Audit all deployments for preview or deprecated versions
List every deployment across every subscription and region, and flag any that use a preview or deprecated model version. This is the foundation for a controlled migration plan.
"""Audit all Azure OpenAI deployments for preview / deprecated model versions.""" from azure.identity import DefaultAzureCredential from azure.mgmt.resource import SubscriptionClient, ResourceManagementClient from azure.mgmt.cognitiveservices import CognitiveServicesManagementClient # Model versions that are preview or deprecated as of 2026 RETIRED_OR_DEPRECATED = { "gpt-4-vision-preview": "retired 2024-08", "gpt-4-1106-preview": "retired 2025-04", "gpt-4-0125-preview": "retired 2025-04", "gpt-4-turbo-2024-04-09": "deprecated — retire Q3 2025", "gpt-35-turbo-1106": "deprecated — retire Q2 2025", "gpt-35-turbo-instruct": "deprecated — retire 2026", } credential = DefaultAzureCredential() sub_client = SubscriptionClient(credential) print(f"{'Subscription':<40} {'Resource':<30} {'Deployment':<30} {'Model':<25} {'Version':<15} {'Status':<25}") print("-" * 165) for sub in sub_client.subscriptions.list(): sub_id = sub.subscription_id sub_name = sub.display_name cog_client = CognitiveServicesManagementClient(credential, sub_id) try: accounts = list(cog_client.accounts.list()) except Exception as e: print(f"{sub_name:<40} (error listing accounts: {e})") continue for account in accounts: if account.kind != "OpenAI": continue rg = account.id.split("/")[4] for deployment in cog_client.deployments.list(rg, account.name): model = deployment.properties.model key = f"{model.name}-{model.version}" if model.version else model.name issue = RETIRED_OR_DEPRECATED.get(model.name, "") if not issue and "preview" in (model.version or "").lower(): issue = "preview version — verify GA status" status = issue or "OK" print(f"{sub_name:<40} {account.name:<30} {deployment.name:<30} {model.name:<25} " f"{model.version or '-':<15} {status:<25}")
Migrate a deployment to the recommended GA version
Update the deployment's underlying model to the GA replacement, verify with test traffic, then update your application code and API version. Do this in a canary environment first.
RG=my-rg AOAI=my-aoai-resource DEPLOYMENT=gpt4-prod # 1) Verify current model az cognitiveservices account deployment show \ --name $AOAI -g $RG --deployment-name $DEPLOYMENT \ --query "{model:properties.model.name, version:properties.model.version, sku:sku.name}" # 2) Update to gpt-4o (GA) az cognitiveservices account deployment update \ --name $AOAI -g $RG --deployment-name $DEPLOYMENT \ --model-name gpt-4o \ --model-version 2024-08-06 \ --model-format OpenAI # 3) Verify update succeeded az cognitiveservices account deployment show \ --name $AOAI -g $RG --deployment-name $DEPLOYMENT \ --query "properties.model" # 4) Test the new model with a probe request curl -X POST "https://$AOAI.openai.azure.com/openai/deployments/$DEPLOYMENT/chat/completions?api-version=2024-10-21" \ -H "Content-Type: application/json" \ -H "api-key: $AOAI_KEY" \ -d '{"messages":[{"role":"user","content":"OK"}],"max_tokens":10}'
api_version may need bumping.Subscribe to model retirement notifications and automate detection
Configure the Azure Service Health RSS feed for AOAI, add an Azure Monitor alert on deprecation warning headers, and route both to a channel your team reads. This means no future retirement surprises you.
"""Middleware to detect deprecation warning headers on every AOAI response.""" import logging import httpx from openai import AzureOpenAI log = logging.getLogger(__name__) class DeprecationWarningMiddleware(httpx.Client): """Wraps the OpenAI SDK's HTTP client to inspect deprecation headers.""" def send(self, request, **kwargs): response = super().send(request, **kwargs) deprecation = response.headers.get("x-ms-model-deprecation-notice") retire_date = response.headers.get("x-ms-model-retirement-date") substituted = response.headers.get("x-ms-deployment-model-substituted") if deprecation or retire_date: log.warning( "AOAI deprecation warning: %s (retire: %s) on %s", deprecation, retire_date, request.url, ) # Emit metric for alerting emit_metric("aoai.deprecation_warning", 1, tags={ "retire_date": retire_date or "unknown", }) if substituted == "true": log.error( "AOAI model auto-substituted: %s -> %s. Response quality may have changed.", response.headers.get("x-ms-original-model"), response.headers.get("x-ms-substituted-model"), ) emit_metric("aoai.model_substituted", 1) return response def emit_metric(name, value, tags=None): """Send to your telemetry backend.""" pass # Wire the middleware into the OpenAI client client = AzureOpenAI( api_key="...", azure_endpoint="...", api_version="2024-10-21", http_client=DeprecationWarningMiddleware(), )
x-ms-model-substituted is P1 (quality regression risk). Deprecation warnings 30+ days out are P3 planning items.Prevention checklist
Ship these seven safeguards once and this error stops appearing in your logs.
- Never deploy a preview model version in production. Preview = evaluation only.
- Add "model version" as a required deployment tag in your Terraform/Bicep — makes audits trivial.
- Log the
x-ms-model-deprecation-noticeheader on every response and alert on it. - Subscribe to the Azure OpenAI model retirements RSS feed and the Service Health blade for your subscriptions.
- When a preview version is used deliberately, put an expiry date on the ticket that renews the decision quarterly.
- For every deployment, document the migration target so migration is a runbook step, not a research task.
- Test the GA successor against your prompt suite before the deprecation window opens — quality differences surface early.
Frequently asked questions
Related errors & hubs
Get the weekly AI-error digest
New fixes, provider status recaps, and one deep tutorial — every Tuesday. 8,400+ engineers.