Guides

Errors & retries

Every error code the API returns, what it means, and whether to retry.

On this page

Errors use the OpenAI error shape, so the OpenAI SDKs raise them as normal exceptions. Branch on error.code (and error.type), never on the message text.

402 Payment Required
{
  "error": {
    "message": "Insufficient balance. Top up to continue.",
    "type": "insufficient_quota",
    "code": "insufficient_credit",
    "param": null
  }
}

The message is in English by default. Send Accept-Language: id to receive it in Bahasa Indonesia. code and type are the same in every language.

Error codes

StatusCodeTypeMeaningWhat to do
400invalid_requestinvalid_request_errorThe body is not valid JSON or names no model.Fix the request. Don't retry.
400max_tokens_exceededinvalid_request_errormax_tokens or max_completion_tokens is above 384,000.Lower it. Don't retry.
400unsupported_contentinvalid_request_errorA message contains an image or another non-text part.Send text only. Don't retry.
401invalid_api_keyinvalid_request_errorThe key is missing, malformed, revoked, or unknown.Check the header and the key. Don't retry.
402insufficient_creditinsufficient_quotaYour available balance is $0.00 or below.Top up, then retry.
402key_budget_exceededinsufficient_quotaThis request would take the key past its monthly budget.Raise or clear the budget in the console, or wait for the next month (WIB).
403insufficient_scopeinsufficient_permissionsThe key lacks the chat:write scope.Use a key with the right scope. Don't retry.
404model_not_foundinvalid_request_errorThe model ID is not served.Use deepseek-flash. Don't retry.
404not_foundinvalid_request_errorUnknown endpoint.Check the path; the base URL ends in /v1.
405method_not_allowedinvalid_request_errorWrong HTTP method for the endpoint.Use POST for chat completions, GET for models.
413request_too_largeinvalid_request_errorThe body is over the request size limit.Shorten the prompt or conversation history.
429rate_limit_exceededrate_limit_exceededMore than 300 requests in a minute on this key.Wait for Retry-After, then retry.
429concurrency_limit_exceededrate_limit_exceededMore than 16 requests in flight on this key.Wait for Retry-After or for a request to finish.
429ip_rate_limitedrate_limit_exceededToo many requests from one IP address.Wait for Retry-After, then retry.
500internal_errorapi_errorUnexpected server error.Retry with backoff.
502provider_unavailableapi_errorThe model provider failed or could not be reached.Retry with backoff.
503billing_unavailableapi_errorBilling is temporarily unavailable; the request was not run.Retry with backoff. You were not charged.
503service_unavailableapi_errorThe service is temporarily unavailable.Retry with backoff.

Other errors returned by the model provider — for example a 400 for a parameter combination it does not support — are forwarded with the provider's own error body.

When to retry

Retry only 429, 500, 502, and 503. Everything else needs a change to the request, the key, or your balance first.

  • 429: wait for the number of seconds in the Retry-After header before trying again.
  • 5xx: use exponential backoff with jitter, for example 1 s, 2 s, 4 s, and give up after a few attempts.
  • Each retry is a new request. It is held, metered, and billed on its own.

The official OpenAI SDKs already retry 429 and 5xx responses a couple of times with backoff, and honour Retry-After. You can raise the limit:

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.larasrouter.com/v1",
    api_key=os.environ["LARAS_API_KEY"],
    max_retries=4,
)

Handle errors by code

Python
import openai

try:
    response = client.chat.completions.create(
        model="deepseek-flash",
        messages=[{"role": "user", "content": "Hello"}],
    )
except openai.APIStatusError as e:
    # The SDK exposes error.code from the response body as e.code.
    if e.code == "insufficient_credit":
        notify_owner("Laras Router balance is empty — top up to resume.")
    elif e.code == "key_budget_exceeded":
        notify_owner("This key reached its monthly budget.")
    else:
        raise

Failed requests and charges

  • A request rejected before it reaches the model — any 400, 401, 402, 403, 404, 413, 429 from Laras Router — is never charged.
  • A request the model provider rejects with a 4xx is not charged; its hold is released.
  • A request that fails with a 5xx, times out, or is interrupted keeps its hold while we reconcile it. You may be charged for usage the provider reports for it; otherwise the hold is released without a charge.

Request ID

Responses to requests that reached billing carry an X-Laras-Request-ID header. It identifies the charge and the hold for that request. Include it when you contact support about a charge. Requests rejected before a hold is placed — for example a 401 — may not carry it.