Guides

Errors and retries

Errors come back with the matching HTTP status code and the error format of the protocol you're using. Telling apart "fix the request" errors from "retry" errors is the key to a reliable integration.

Error format

OpenAI-compatible protocol:

json
{
  "error": {
    "message": "insufficient user quota, remaining: $0.01",
    "type": "new_api_error",
    "code": "insufficient_user_quota"
  }
}

Anthropic native protocol:

json
{
  "type": "error",
  "error": { "type": "invalid_request_error", "message": "..." }
}

Status codes at a glance

StatusMeaningWhat to doRetry?
400Bad request: missing fields, wrong format for the protocol, or a parameter the model doesn't supportFix the request based on error.messageNo
401API key missing, invalid, deleted or expiredCheck the header and the key's status; see AuthenticationNo
403Not enough balance or key budget, or the key isn't allowed to use this modelTop up, or adjust the key's budget and model limitsNo
404Path not found, usually a wrong base URLThe OpenAI SDK includes /v1; the Anthropic and Gemini SDKs don'tNo
429Too many requestsLower concurrency and retry with exponential backoffYes
500 / 502Temporary service errorRetry laterYes
503No capacity for this model right now, or the model ID doesn't existCheck the model ID; if it's right, retry laterYes
504Timed outRetry; for image tasks, fetch the result by task IDYes

Retry strategy

Retry only on 429, 5xx and network errors. Other 4xx errors won't succeed on retry. Use exponential backoff with jitter:

retry.py
import random, time
from openai import OpenAI, APIConnectionError, APIStatusError, RateLimitError

client = OpenAI(api_key="sk-...", base_url="https://api.flyrouter.ai/v1", max_retries=0)

def chat(messages, attempts=5):
    for i in range(attempts):
        try:
            return client.chat.completions.create(model="gpt-6.1-sol", messages=messages)
        except (RateLimitError, APIConnectionError) as e:
            err = e
        except APIStatusError as e:
            if e.status_code < 500:
                raise  # request, auth or balance problem; retrying won't help
            err = e
        time.sleep(min(2 ** i, 30) + random.random())
    raise err

The official OpenAI and Anthropic SDKs already retry twice on 429 and 5xx by default. For most apps, raising max_retries is all you need.

Timeouts

  • Large models can take seconds to tens of seconds before the first token, longer when reasoning. Set your client read timeout to at least 10 minutes, or use streaming.
  • Image generation also needs a timeout of 10 minutes or more.

Billing and failed requests

  • An estimated amount is held when a request starts and settled against actual usage when it finishes.
  • Requests that fail without producing output are refunded in full.
  • If a streaming request is cut off midway, the part already generated is billed.

Contact support

If a problem keeps happening, contact us with the request time, the model ID and the full error message (never include your API key).

FlyRouter

One key, every top AI model