Home

Fix this error · Payments and AI APIs

Fix: 429 You exceeded your current quota, please check your plan and billing details

Fix OpenAI 429 insufficient_quota: billing codes vs the rate-limit 429, retry with backoff only for rate limits, and openai-node maxRetries.

This 429 from the OpenAI API is a billing error. Your organization or project has no credit left, or it hit a spend or usage limit. Waiting and retrying does not help: add credits or raise the limit in the API platform's billing settings, then try again. A different 429, Rate limit reached for …, means you sent requests too fast, and that one is fixed by slowing down and retrying with backoff.

FactDetail
Error429 You exceeded your current quota, please check your plan and billing details.
Error typeinsufficient_quota (newer responses also carry a specific code, such as credit_balance_exhausted)
Not the same as429 Rate limit reached for …, a temporary rate limit
Where you see itServer logs, a RateLimitError from the openai package, the API response body
Usual causeNo prepaid credits, or an organization or project spend limit reached
Usual fixAdd credits or raise the limit at platform.openai.com. Do not retry until you have
BugTape catches itYes, when the error is thrown out of a request (Next.js onRequestError, uncaught). With Express, call captureException, because the handler skips 4xx

What the error means

The OpenAI API answers 429 for two different problems. One is a rate limit: too many requests or tokens in a short time. It clears on its own, and the response can carry a Retry-After header. The other is a billing limit: the account cannot pay for more requests. It does not clear until someone changes the billing settings.

The You exceeded your current quota message has type: "insufficient_quota". OpenAI's current error reference lists the billing 429s by error.code and notes that the broader error.type can still be insufficient_quota:

CodeMeaning
credit_balance_exhaustedThe organization has no prepaid credits left
organization_spend_limit_exceededThe organization reached its own monthly spend limit
project_spend_limit_exceededThe project reached its monthly spend limit
organization_usage_limit_exceededThe organization reached the usage limit OpenAI assigned to it

The openai package for Node.js turns every 429 into a RateLimitError. Its message is the status followed by the API's message, which is why the log line starts with 429. The error object has status, code and type, so your code can tell the two cases apart.

Common causes

  1. No prepaid credits. API usage is billed separately from a ChatGPT subscription. A ChatGPT Plus plan does not include API usage.
  2. A spend limit was reached. The organization or project has a monthly limit, and this month's usage hit it.
  3. The key belongs to a different organization or project. The key you use is in a project or organization without credits, while the one you added credits to is another.
  4. The organization usage limit. OpenAI assigns each organization a monthly usage limit, separate from the spend limits you set.
  5. The rate-limit 429 instead. The message starts with Rate limit reached for. A loop, concurrent jobs or a shared key send more requests or tokens per minute than the limit allows.

How to fix it

Fix billing, then send the next request

Open the API platform (platform.openai.com), go to Settings, Billing for credits, and Settings, Limits for organization and project limits. Check that the key you use belongs to the project you funded. Retrying a billing, spend or quota error does not restore access.

Tell the two 429s apart in code

import OpenAI from 'openai';

const BILLING_CODES = new Set([
  'insufficient_quota',
  'credit_balance_exhausted',
  'organization_spend_limit_exceeded',
  'project_spend_limit_exceeded',
  'organization_usage_limit_exceeded',
]);

export function isBillingError(err: unknown): boolean {
  return (
    err instanceof OpenAI.RateLimitError &&
    (err.type === 'insufficient_quota' || BILLING_CODES.has(err.code ?? ''))
  );
}

Retry only the rate limit, with backoff

The openai package already retries 429s twice by default, with a short exponential backoff, and waits for Retry-After when it is 60 seconds or less (longer values fall back to its own backoff). When the server sends an x-should-retry header, the package follows it. Otherwise it retries every 429, including billing ones, which only delays the error. Turn the built-in retries off if you run your own loop, so the two do not multiply.

const client = new OpenAI({ maxRetries: 0 });

export async function createWithRetry(params: OpenAI.Responses.ResponseCreateParamsNonStreaming, attempts = 5) {
  for (let i = 0; ; i++) {
    try {
      return await client.responses.create(params);
    } catch (err) {
      if (isBillingError(err) || !(err instanceof OpenAI.RateLimitError) || i >= attempts - 1) throw err;

      const retryAfter = Number(err.headers?.get('retry-after'));
      const base = Number.isFinite(retryAfter) && retryAfter > 0 ? retryAfter * 1000 : 500 * 2 ** i;
      await new Promise((r) => setTimeout(r, base + Math.random() * 250)); // add jitter
    }
  }
}

To keep the package's retries, set the count instead: new OpenAI({ maxRetries: 5 }), or per request as the second argument, { maxRetries: 5 }.

Lower the request rate

Batch work, cap how many requests run at once, and avoid sharing one key between unrelated jobs. Rate limits apply to the whole organization, so teammates' usage counts too. The response headers x-ratelimit-remaining-requests and x-ratelimit-remaining-tokens show how close you are.

Return a useful answer to your own users

A billing error is not something the user can fix. Answer with a clear message and a status your client treats as temporary, and alert yourself.

if (isBillingError(err)) {
  return Response.json({ error: 'The assistant is unavailable right now.' }, { status: 503 });
}

How to catch it in production with BugTape

A quota error affects every user at once and does not go away, so you want to hear about it the first time. How BugTape sees it depends on where it surfaces.

  • Next.js on the Node.js runtime. A RateLimitError that is thrown out of a Route Handler, Server Action or page is reported through onRequestError. The Edge runtime is not supported.
  • Uncaught in Node.js. An uncaught exception or unhandled rejection is reported automatically.
  • Express. The BugTape Express handler reports only errors that end in a 5xx. The OpenAI error carries status: 429, so next(err) with it is skipped. Report it yourself.
  • Caught and handled. If you catch it and return a friendly answer, nothing is reported unless you call captureException.
import * as bugtape from '@bugtape/node';

bugtape.init({ service: 'api' }); // reads BUGTAPE_KEY

try {
  return await createWithRetry(params);
} catch (err) {
  if (err instanceof OpenAI.RateLimitError) {
    bugtape.captureException(err, {
      severity: isBillingError(err) ? 'critical' : 'medium',
      extra: { code: err.code, type: err.type },
    });
  }
  throw err;
}

In a serverless function, await bugtape.flush() before the function returns so the report is sent. In Python, the openai package raises openai.RateLimitError. The BugTape Python SDK reports it when it is uncaught, when you log it at ERROR, or when you call bugtape.capture_exception() inside the except block.

Every request that fails the same way groups into one issue with a count, so a quota outage is one issue that grows. Set release so that when you mark it fixed, a report from a newer release reopens it as a regression. Your coding agent can read the issue over MCP (npx -y bugtape connect claude, or cursor or codex) and propose the retry or error-handling change. You review the pull request.

FAQ

I just added credits. Why do I still get the error?

Check that the credits went to the same organization as the key you use, and that neither the organization nor the key's project has reached a spend limit. A project spend limit stops that project even when the organization has credit.

Does ChatGPT Plus include API access?

No. ChatGPT and the API platform have separate billing. API usage is paid in the API platform's billing settings.

Should I retry insufficient_quota with exponential backoff?

No. Backoff is for the temporary rate limit. A billing error returns the same answer until the billing settings change, so retrying only delays your error and sends more requests. Check error.type and error.code and stop.

How do I know whether a 429 is a rate limit or a quota problem?

Read the message and the fields. A rate limit says Rate limit reached for …, may include a Retry-After header, and clears with time. A billing error says you exceeded your quota, or has a code such as credit_balance_exhausted or a spend-limit code.

Sources

All guides: Fix an error.

Start free. Free plan · No credit card · Set up in minutes. Or try the live demo first.