Core API

Errors & rate limits

Parse gateway and upstream errors, decide when to retry, and collect a trace identifier.

On this page

This page is for developers diagnosing failed production requests or designing retry behavior.

Gateway-generated 401, 402, and 429 responses use a string in error. Upstream errors commonly use an OpenAI-compatible object. Clients must handle both.

JSONSyntax highlighted
{"error":"Unauthorized: Missing API key"}
JSONSyntax highlighted
{"error":{"message":"The selected model rejected the request.","type":"invalid_request_error"}}

Status codes#

StatusMeaningRetry?Action
400Invalid request, including unsupported masked image edits.noFix the body or form fields.
401Missing or unknown API key.noFix server-side authentication.
402Expired, disabled, parent-disabled, or depleted key.noInspect key state and balance.
403Upstream authorization or policy rejection.usually noInspect the returned upstream body.
404Unrecognized path prefix, or a model that cannot serve the requested endpoint.noCorrect the endpoint.
408Upstream timeout response.before output onlyRetry with bounded backoff if the operation is safe.
413Upload too large, including image edits over the combined 8 MB limit.noShrink or split the upload.
429CLSSAI free daily pool exhaustion or an upstream limit.laterRead the body and wait before retrying.
502All gateway connection attempts failed.yesRetry with bounded backoff.
503Gateway configuration or upstream availability failure.yesRetry later and report the trace if persistent.
504Upstream gateway timeout.yesRetry before output with bounded backoff.

CLSSAI does not impose a per-key RPM limit. Free users share a global daily pool; exhaustion returns the gateway 429 string below. Other 429 responses come from the upstream API and may use a different body or headers.

JSONSyntax highlighted
{"error":"Too Many Requests: Daily Free Quota Exhausted","message":"The global free tier limit for today has been reached. Please add funds."}

Parse both shapes and retry safely#

JavaScriptSyntax highlighted
const retryable = new Set([408, 429, 502, 503, 504]);

async function requestWithBackoff(url, init, attempts = 3) {
  for (let attempt = 0; attempt < attempts; attempt += 1) {
    const response = await fetch(url, init);
    if (response.ok) return response;

    const body = await response.json().catch(() => ({}));
    const message = typeof body.error === "string"
      ? body.error
      : body.error?.message ?? body.message ?? `HTTP ${response.status}`;

    if (!retryable.has(response.status) || attempt === attempts - 1) throw new Error(message);
    await new Promise((resolve) => setTimeout(resolve, 500 * (2 ** attempt)));
  }
  throw new Error("Request failed");
}

Do not retry after an SSE stream has emitted its first event. The gateway itself makes at most two attempts for connection-level 502, 503, and 504 failures, except for request bodies too large to replay.

Trace a request#

Inference responses do not add an application-specific request ID. Record the cf-ray response header on every response, plus x-generation-id when an OpenAI-compatible response includes it. Share those identifiers, the timestamp, endpoint, and status with support; never share the API key.

Common mistakes#

  • Do not assume error is always an object.
  • Do not infer that a path exists from a 401; authentication happens before route selection.
  • Do not invent a per-key RPM threshold.
  • Include /v1 in the OpenAI SDK base URL and omit it from the Anthropic SDK base URL.
  • Keep server calls out of the browser, preserve complete variant IDs, and check empty streaming choices arrays.
  • Record cf-ray and, for OpenAI-compatible routes, x-generation-id when present.
Need a hand?

Find answers to common questions or diagnose a failed request.

Frequently asked questions →Troubleshoot errors →