PARAS MADAN
All writing

Latest in AI

How to Fix OpenAI API 429 Errors: Rate Limits, Quota and Spending Caps

Identify the exact cause before retrying, use a small Python classifier, and restore traffic without creating a retry storm.

An OpenAI API 429 error needs two different kinds of response. Temporary request throttling calls for slower traffic and a delayed retry. An exhausted balance or spending cap needs a billing or settings decision. Adding the same retry loop to both keeps the application busy without fixing the problem.

Start with the response body, especially error.code and error.type, and keep the HTTP status, request ID and timestamp alongside it so you can connect the error to the request that produced it. This guide covers OpenAI's API, not the usage limits shown inside the ChatGPT app. The error names below were checked against the current documentation on November 6, 2026.

1. Match the error to the right action

OpenAI's API error reference distinguishes the following cases. A billing error can still carry the broad type insufficient_quota, so read its more specific code when present.

Error code or signalWhat to checkNext action
credit_balance_exhaustedOrganization prepaid balanceAsk the billing owner to replenish credits if continued usage is approved.
organization_usage_limit_exceededOpenAI-assigned monthly usage limitRequest a higher approved limit.
organization_spend_limit_exceededOrganization's enforced spending capReview the cap with its owner, or wait for the monthly reset.
project_spend_limit_exceededThis project's enforced spending capReview this project's cap, rather than changing unrelated projects.
rate_limit_error typeRequest and token throughputPace traffic and use a delayed, bounded retry.
slow_down codeHow quickly traffic increasedReduce the rate and ramp up gradually.

Do not automatically remove a financial limit to clear an error. It may be the control that is stopping an unexpected bill.

For example, if staging works but production fails, compare their project identifiers before changing anything. A successful request from your laptop proves that one credential-and-project combination works; it does not establish that the production service is using it.

2. Separate a spending alert from an enforced cap

The current spend-limit guide supports both alerts and hard limits. An alert sends a notification while traffic continues. A hard limit can make affected requests return 429. Organization and project limits can both apply, and the OpenAI-assigned usage limit is a separate control.

For an organization cap, check Organization limits. For a project cap, open that project's Settings, then Limits. Review whether hard enforcement is enabled and compare the applicable limit with current usage. Changes take time to propagate, and enforcement can allow a small overrun rather than stopping at an exact cent.

Write down the error code and the setting you changed, then send one small verification request before reopening the queue. If the new error points to a different control, investigate that control instead of repeatedly raising the first limit.

3. For temporary throttling, inspect the exhausted budget

The rate-limit documentation describes separate request and token limits, scoped to organizations and projects rather than individual users. Some model families share a limit.

Inspect these response headers when available:

  • x-ratelimit-remaining-requests and x-ratelimit-reset-requests
  • x-ratelimit-remaining-tokens and x-ratelimit-reset-tokens
  • x-ratelimit-remaining-project-tokens and x-ratelimit-reset-project-tokens
  • Retry-After

A request shortage suggests too many calls. A token shortage suggests too much text passing through the service. Reducing concurrency can help either case, but shortening unnecessary context directly addresses token pressure.

Consider a hypothetical worker pool with eight workers, each issuing ten requests per minute. That is 80 requests per minute before retries. If the applicable allowance were 60, adding backoff would not make that sustained workload fit. You would need to queue work, reduce the arrival rate or obtain more capacity. Those numbers are an example, not an OpenAI plan allowance.

Before requesting a higher allowance, I would check the scheduler and retry policy, since extra capacity can hide a burst problem without fixing it. A job that starts every worker at the same instant may exceed a short-window limit even when its minute-long average looks reasonable.

4. Classify before your application decides to retry

This small Python function turns a decoded 429 response body into an internal action label. It does not make requests, change billing or sleep. Responses with unrecognized types and malformed bodies stop for inspection rather than being assumed safe to retry.

BILLING_ACTIONS = {
    "credit_balance_exhausted": "review_credit_balance",
    "organization_usage_limit_exceeded": "review_approved_usage_limit",
    "organization_spend_limit_exceeded": "review_org_spend_limit",
    "project_spend_limit_exceeded": "review_project_spend_limit",
}


def action_for_429(body):
    if not isinstance(body, dict):
        return "inspect_error"
    error = body.get("error")
    if not isinstance(error, dict):
        return "inspect_error"

    code = error.get("code")
    kind = error.get("type")
    if isinstance(code, str) and code in BILLING_ACTIONS:
        return BILLING_ACTIONS[code]
    if kind == "insufficient_quota" or code == "insufficient_quota":
        return "review_billing_details"
    if code == "slow_down":
        return "reduce_rate_then_retry"
    if kind == "rate_limit_error":
        return "bounded_delayed_retry"
    return "inspect_error"


# Synthetic examples, not captured customer responses.
assert action_for_429({"error": {
    "type": "insufficient_quota",
    "code": "project_spend_limit_exceeded",
}}) == "review_project_spend_limit"

assert action_for_429({"error": {
    "type": "rate_limit_error",
    "code": "slow_down",
}}) == "reduce_rate_then_retry"

assert action_for_429({}) == "inspect_error"

Pass the full parsed JSON body, not just its inner error object. Only use this classifier after confirming HTTP status 429. The specific billing codes take priority over the broad type.

The function and synthetic cases were checked locally. No paid API calls or account-setting changes were made for this guide. It is a starting point for error routing, not a complete queue or retry implementation.

5. Put one layer in charge of retries

The official OpenAI Python SDK retries eligible failures twice by default. It exposes max_retries to change that behavior, including 0 to disable SDK retries. Failed API requests expose a request ID through APIStatusError.

Before adding your own loop, check the installed SDK's behavior and your job runner's retry policy. Three application attempts, each allowing an initial SDK request plus two retries, can produce nine underlying attempts. Add another queue-level retry and the multiplication becomes harder to notice.

If an application-level worker owns classification, delay and retry budgets, configure the SDK deliberately rather than leaving two independent policies in charge. Disabling SDK retries also removes its automatic handling of other eligible failures; your application must decide what to do with those separately.

For a temporary rate error, OpenAI's troubleshooting guidance says to honor a valid Retry-After, otherwise use exponential backoff with jitter. Bound both attempt count and total retry time. Failed requests can themselves consume rate allowance. Check your SDK version's handling of long server delays rather than assuming every version waits indefinitely.

Once a streaming response has delivered output, do not automatically replay the entire request. Track what the application has already shown or executed before deciding how recovery should work.

Choose budgets that fit the job. For an interactive request, a server-requested delay longer than the user's deadline should end or defer the job, not be shortened to squeeze in another attempt. For background processing, put the work back into a scheduled queue instead of holding a worker asleep for a long period.

A short recovery checklist

Before restoring the full workload:

  1. Confirm the production organization, project and model match the investigation.
  2. Identify one error class and record the corrective action.
  3. Verify one request, then a small paced batch.
  4. Watch success rate, queue age, request volume and token volume together.
  5. Reopen capacity gradually. Keep failed jobs visible and avoid replaying already completed application actions.

If the error remains unexplained, collect the timestamp with time zone, request ID, model, exact error code, relevant limit and changes attempted. Keep API keys, authorization headers and private prompt contents out of the support packet.

I'm Paras, a technical writer working with AI and developer-tool teams.

I help turn API edge cases into clear documentation and practical technical content.

Book a 30-minute call.