LowCodeStacks™
Sign in

Azure OpenAI 429 errors: why you're throttled below quota, and how to fix it

A 429 from Azure OpenAI rarely means you're out of quota. The rate limit counts estimated tokens including max_tokens, checks requests in one to ten second windows, and can be cut temporarily on shared capacity. Read the headers, then fix the real cause.

AI & agentsFix a problem6 min read

Checked against Microsoft Learn · 4 sourcesPosted by the Maker DeskHow we write guides

A 429 "Too Many Requests" from Azure OpenAI in Microsoft Foundry is the most misread error on the platform. The usage charts say you're well under quota, yet calls fail, so people request more quota and nothing changes. The rate limit and the usage metrics measure different things, and there are four different reasons for a 429 that each need a different fix. This guide shows how to tell them apart and what to do for each.

Read the error before you act

Every response carries rate-limit headers. On a 429, read them before you change anything:

HeaderMeaning
x-ratelimit-limit-requests, x-ratelimit-limit-tokensThe deployment's limits per minute, as enforced right now
x-ratelimit-remaining-requests, x-ratelimit-remaining-tokensWhat's left in the current minute
x-ratelimit-reset-requests, x-ratelimit-reset-tokensHow long until each counter resets
retry-after-msOn a 429: how long to wait before trying again

Then match the message to its cause:

What the message saysThe causeWhat fixes it
"Requests to … have been limited" or "Rate limit is exceeded"You went over the deployment's TPM or RPMGive the deployment more TPM, rebalance from a quiet one, or request more quota
"The service is temporarily unable to process your request" or "high demand"Shared capacity is constrained, usually brieflyRetry after retry-after-ms; if it persists, consider provisioned throughput
429s while x-ratelimit-limit-tokens is lower than the TPM you configuredA temporary reduction of your effective limit to protect the shared poolRetry with backoff; it normally clears within hours; spread or ramp traffic
Rate limited while token metrics look lowYour requests reserve more tokens than they use, through max_tokensLower max_tokens to the size of the answers you expect

Microsoft says it plainly: many customers treat capacity-related 429s as quota problems and request increases that can't help.

Why you are throttled below quota

The usage metrics in Azure Monitor show billed tokens from successful requests. The rate limit is applied to requests as they arrive, with an estimate, and that estimate is what fills the bucket:

  • The token estimate includes max_tokens (and best_of), not just the prompt. A request that expects a 200-token answer with max_tokens set to 4,000 reserves 4,000 against your limit, even though you're billed for the real output. The estimate is also based partly on character count, so it's approximate and can trip earlier than an exact count would.
  • Requests per minute are checked in short windows, typically 1 or 10 seconds. A 600 RPM deployment allows about 10 requests a second; a burst of 30 in one second is throttled even if the minute's total is fine.
  • Rejected and failed requests still count. A request refused for being too long (a 400) can count against the limit without appearing in billed usage. Retrying without backing off makes it worse.
  • Shared capacity can be reduced temporarily. Standard, pay-per-token deployments share a pool. When demand nears its limits, the service lowers a deployment's effective rate for a while. You can see it: the header's limit drops below your configured TPM.
  • Quota must sit on the deployment that gets the traffic. Approved subscription quota does nothing until it's allocated to that deployment, and enforcement across a distributed service isn't perfectly precise either.

Tip

Watch x-ratelimit-remaining-tokens and x-ratelimit-remaining-requests in your own code and slow down before the 429 arrives, rather than after.

Retry properly

Honour retry-after-ms when it's present; otherwise back off exponentially with random jitter, and cap the attempts. The openai Python package already does this for 429s, with two retries by default; raise it on the client rather than writing your own loop:

python
from openai import AzureOpenAI

client = AzureOpenAI(
    azure_endpoint="https://<your-resource>.openai.azure.com/",
    api_key="<your-api-key>",
    api_version="2024-10-21",
    max_retries=5,  # exponential backoff with jitter, honours retry-after
)

If you use a retry library such as tenacity or Polly instead, set the SDK's max_retries to 0 first. Otherwise every attempt of yours can trigger up to two SDK retries of its own, and the extra requests count against the same limit.

Then shrink what each request reserves:

  • Set max_tokens to the smallest value your scenario needs. This is the single most common fix.
  • Leave best_of at 1 unless you really need several completions; each increment multiplies the token count.
  • Shorten prompts where you can.
  • Spread traffic. Ramp new workloads up gradually; avoid sharp spikes; split across deployments or regions when one deployment can't carry the load; queue work that doesn't need an immediate answer.

Check and rebalance quota

Quota is tokens per minute per subscription, region, model and deployment type, and each deployment takes a slice of it.

  1. Open Manage > Quota in the Foundry portal. The Token per minute tab shows each deployment's allocation and usage; the pencil in Affiliated deployments using shared quota moves TPM between deployments. Changes take up to 15 minutes.
  2. To see it you need the Cognitive Services Usages Reader role at the subscription scope, not on the resource group or the resource.
  3. For a script or an alert, the Usages API returns every quota line in a region with currentValue and limit; the Model Capacities API says where a model can still be deployed and how much capacity is free.
  4. When the whole subscription is short, submit Microsoft's quota increase form. Requests are handled in order, and priority goes to subscriptions that actively use what they have.

When to escalate or move to provisioned throughput

SituationDo this
Occasional 429s that clear with retry-after-msRetry. This is normal on standard deployments and not a defect
429s in development or testingOften fine; a small deployment there is a cost guardrail
Sustained 429s in production while under the quota you were approved forCheck the allocation on the deployment first, then open a support request
A quota increase that doesn't show in the effective limitsVerify the deployment-level allocation, then escalate
Frequent 429s on a latency-sensitive production workloadMove to provisioned throughput: reserved capacity with guaranteed limits, and spillover to a standard deployment for bursts beyond it

Provisioned deployments measure utilisation differently and don't share the pool, so they're the answer for work that needs the same throughput at the same latency every minute. For everything else, the fixes above are usually enough.

Sources

Did this fix it?

Comments

No comments yet. Share what worked for you.

Sign in to comment. Comments show under a display name you choose, never your email.