PaddlePaddle/PaddleOCR · warning · RateLimitError

Rate limit exceeded

Error message

Rate limit exceeded: ${text}

What it means

RateLimitError is thrown when the API answers HTTP 429 — you exceeded the allowed request rate or quota for your key/tier. It extends APIError with statusCode fixed at 429, and the message embeds any server explanation. This error is by design retryable after waiting.

Solutions

  1. Retry with backoff honoring the server's Retry-After guidance — start the next attempt after at least 1-2 seconds and double on repeat 429s
  2. Cap concurrency of parallel submissions (e.g. p-limit with 2-4) and add spacing between polls
  3. Increase the poll interval / maxWaitTime budget so status checks are less frequent
  4. If sustained, request a quota increase or distribute across keys/environments as allowed by your plan

Example fix

// before
const results = await Promise.all(files.map(f => client.extractFile(model, f, {})));

// after
import pLimit from "p-limit";
const limit = pLimit(3);
const results = await Promise.all(files.map(f =>
  limit(() => retryOn429(() => client.extractFile(model, f, {})))
));
Defensive patterns

Strategy: retry

Type guard

function isRateLimitError(e: unknown): e is RateLimitError {
  return e instanceof RateLimitError;
}

Try / catch

async function withRateLimit<T>(fn: () => Promise<T>, maxRetries = 5): Promise<T> {
  for (let attempt = 0; ; attempt++) {
    try { return await fn(); }
    catch (e) {
      if (e instanceof RateLimitError && attempt < maxRetries) {
        await sleep(Math.min(2 ** attempt * 1000, 30_000) + Math.random() * 500);
        continue;
      }
      throw e;
    }
  }
}

Prevention

When it happens

Trigger: Tight poller loops hitting getJobStatus too frequently; submitting many files in a parallel loop; bursty batch status checks; shared keys used by multiple services; free-tier keys with low QPS ceilings.

Common situations: Fan-out uploads without concurrency limits; polling intervals shorter than the API allows; retries after errors amplifying request volume; month/quota exhaustion near billing boundaries; multiple team members sharing one key.

Related errors


AI-assisted analysis of PaddlePaddle/PaddleOCR@2661c7c0ef (2026-08-14). Data as JSON: /api/errors/b3d7c8834dc20163. Report an issue: GitHub.

Appendix: source

Thrown at api_sdk/typescript/src/internal/http.ts:241

      clearTimeout(timeoutID);
      signal?.removeEventListener("abort", abort);
    }

    if (resp.ok) return resp;

    let text = await resp.text();
    try {
      const payload = JSON.parse(text) as { msg?: string; message?: string; errorMsg?: string };
      text = payload.msg || payload.message || payload.errorMsg || text;
    } catch {
      // Keep raw response text.
    }
    if (resp.status === 401 || resp.status === 403) {
      throw new AuthError(`Authentication failed: ${text}`);
    } else if (resp.status === 400) {
      throw new InvalidRequestError(`Bad request: ${text}`);
    } else if (resp.status === 429) {
      throw new RateLimitError(`Rate limit exceeded: ${text}`);
    } else if (resp.status === 503 || resp.status === 504) {
      throw new ServiceUnavailableError(resp.status, `Service unavailable: ${text}`);
    } else {
      throw new APIError(resp.status, text);
    }
  }
}

function requireJobId(data: SubmitResponse): string {
  if (!data || typeof data.jobId !== "string" || data.jobId.length === 0) {
    throw new ResponseFormatError("Submit response is missing jobId.");
  }
  return data.jobId;
}

View on GitHub (pinned to 2661c7c0ef)