openai-compatible-client-errors · EN · 2026-10-18

Your OpenAI-Compatible Client Errors Out: Mapping the Aggregator's Error Responses to Each Vendor's Real Ones

A practical guide to reading error responses from an OpenAI-compatible aggregator: how to tell aggregator-originated errors (auth, balance, rate limiting at the gateway) from relayed upstream vendor errors, how the OpenAI error envelope is usually preserved, and what remediation to try for each class of failure.

Why error responses get confusing

When you point an OpenAI-compatible client at an aggregator, a single failing request can originate in one of several places: your client, the aggregator gateway, the routing layer, or the upstream model vendor. All of them tend to come back wrapped in the same OpenAI-style error envelope, so the JSON shape alone does not tell you where the problem lives.

Being able to classify the error quickly saves a lot of debugging time, especially because the correct fix is different for each origin.

The common OpenAI error envelope

Most OpenAI-compatible APIs return errors like this:

{
  "error": {
    "message": "...",
    "type": "...",
    "param": null,
    "code": "..."
  }
}

And over HTTP, status codes matter more than the body text. Treat the HTTP status as your first signal, then the type/code fields, then the message body.

A useful mental model:

  • 4xx from the gateway → usually your request, your key, or your balance.
  • 4xx relayed from the vendor → usually your request as the vendor interpreted it (bad parameters, unsupported feature for that model, content policy).
  • 429 → could be either the gateway's own throttle or the vendor's; the distinction matters for retry strategy.
  • 5xx → almost always upstream or a transient gateway/routing problem.

Signals that an error came from the aggregator itself

Aggregator-originated errors typically appear before a vendor is ever contacted. Common patterns:

  • Authentication failures for an invalid or missing API key. The message usually refers to the key/token, not to a model.
  • Balance or quota exhaustion at the aggregator level. Since payment is prepaid (e.g., topped up in USDC on Base), an out-of-credit condition is an aggregator concept, not a vendor one.
  • Model routing errors: a model identifier the gateway does not recognize, or a model that exists but is not currently routable.
  • Gateway-level rate limiting: too many requests per unit time hitting the aggregator regardless of upstream capacity.
  • Request validation performed by the gateway before forwarding (malformed JSON, missing required fields).

Heuristics that help:

  • If the message mentions your account, key, credit, or a routing/model registry concept, it is almost certainly the gateway.
  • If the error appears instantly (no meaningful latency), suspect the gateway.
  • If the same request succeeds against another model name, suspect routing.

Signals that an error was relayed from the vendor

The aggregator forwards the upstream response, often preserving status and body. Telltales:

  • The message references the vendor's model naming, its safety system, or its context window limits.
  • The error mentions a parameter the vendor rejects even though it is valid OpenAI syntax (each vendor has slightly different support surfaces).
  • The status is a vendor-style 400/422 for content policy or unsupported modalities.
  • The type/code strings look vendor-specific rather than the generic OpenAI set.
  • The request took a while before failing, suggesting it reached an upstream service.

Some aggregators normalize vendor errors into OpenAI-style types. In that case, the status code and the wording of the message are your best clues.

A practical classification checklist

When a call fails, run this in order:

  1. Read the HTTP status. 401/403 → credentials. 402 or a balance-specific 4xx → credit. 404 → model or route. 429 → throttling. 5xx → upstream/transient.
  2. Check whether the message references your account, key, or balance. If yes, it's the gateway.
  3. Check whether the message references model behavior, safety, or vendor-specific parameters. If yes, it's the vendor.
  4. Look at latency. Instant failures are usually local to the gateway; slow failures usually reached upstream.
  5. Reproduce with a minimal request. Strip optional parameters and try a different model to isolate routing vs. parameter issues.

What to do for each class

Credentials and access (401/403)

  • Confirm the key is present and not truncated by an environment variable or config loader.
  • Confirm you are sending it in the expected header (usually Authorization: Bearer ...).
  • Rotate the key if you suspect leakage; then update clients and CI secrets.

Balance and quota at the aggregator (prepaid)

  • Check your account balance on the aggregator side.
  • If you use prepaid top-ups, confirm the top-up transaction settled and was credited.
  • Remember the pricing model: you pay official price × 1.3, so a depleted balance is a balance issue, not a bug in the API.
  • If you are a key contributor receiving credit back (official price × 1.1, or × 1.2 for premium), confirm the credit was applied to the account you are calling from.

Unknown or unroutable model (404 or a gateway 400)

  • Verify the exact model identifier string; aliases differ between providers.
  • Confirm the model is available to your account tier.
  • Try a known-good model with the same key to separate key problems from model problems.

Rate limiting (429)

  • If the message references the gateway, back off and add jitter; consider spreading load across models.
  • If it references the vendor, the vendor is throttling the upstream route; retry with exponential backoff and reduce concurrency.
  • Distinguish the two before scaling retries, or you may amplify throttling.

Parameter and validation errors (400/422)

  • Reduce the request to the minimum and add parameters back one at a time.
  • Check vendor-specific support: not every model honors every OpenAI parameter (e.g., certain tool-calling, response formats, or sampling options).
  • If the error mentions a field name, that field is usually the culprit.

Content policy and safety (400/403 depending on vendor)

  • Treat as a vendor-side decision; rewording or restructuring the prompt is the usual remedy.
  • Do not retry the identical request in a tight loop.

Upstream and transient failures (5xx)

  • Retry with backoff; these are frequently transient.
  • If persistent for one model, switch models while you investigate.
  • Log the request ID if the response includes one; it helps the aggregator trace the upstream call.

Logging and observability tips

  • Log status code, error type, error code, and a request/trace ID on every failure.
  • Record latency alongside the error; it is one of the cheapest origin signals.
  • Do not log full request bodies containing user data unless you have a clear retention policy.
  • Build a small mapping in your client from status + message keywords to a retryable/not-retryable classification.

Writing resilient client code

  • Centralize error handling in one place so retry policy is consistent.
  • Classify before retrying: retry 5xx and most 429s; do not blindly retry 4xx validation or policy errors.
  • Use exponential backoff with jitter and a maximum attempt count.
  • Surface the original error message to developers; it is the fastest path to the correct fix.

Summary

The error envelope looks the same everywhere, so classify by origin instead of by shape. Ask three questions: did it originate before the vendor was contacted (credentials, balance, routing, gateway throttle), did the vendor reject the request (parameters, policy, context), or is it transient (5xx, throttling)? Answer those and the fix — rotate a key, top up, adjust parameters, back off, or retry — becomes obvious.