Reading HTTP Status Codes From the Aggregator: Which Layer Returned the Error
Learn how to tell whether a 401, 403, 404, 422, 429, or 500 response came from the aggregator gateway or from the upstream model vendor, so you debug in the right layer instead of guessing.
When a request through an LLM API aggregator fails, the status code alone rarely tells you where the problem lives. The same 429 can mean the aggregator throttled your key, or the upstream vendor throttled the aggregator's shared capacity. Reading the surrounding signals — response body, headers, request ID format, and timing — tells you which layer to debug.
The two layers in a proxied request
A request through the aggregator passes through roughly two stages before it reaches a model:
- Aggregator gateway — authenticates your API key, checks balances and routing, enforces its own quotas, then forwards the request.
- Upstream vendor — the provider actually running the model (for example Claude, GPT, DeepSeek, Qwen, GLM, or Kimi). It applies its own auth, model availability, and rate limits.
Errors can originate in either layer, and many vendors return similarly shaped error bodies, which is why attribution matters.
What each layer typically owns
| Concern | Usually aggregator | Usually upstream vendor |
| --- | --- | --- |
| Your API key format / validity | Yes | No |
| Account balance / top-up state | Yes | No |
| Vendor credential or org permission | No | Yes |
| Model name exists at that vendor | Sometimes | Yes |
| Per-key quotas, concurrency | Yes | Sometimes |
| Model-side throttling | No | Yes |
| Prompt/schema validation | Rarely | Often |
| Vendor-side outage | No | Yes |
Use this as a first hypothesis, not a rule. Vendors can reject requests for reasons that look like gateway errors, and aggregators often pre-validate before forwarding.
Read the response body and headers first
Before memorizing codes, check four things:
- Error envelope shape — many vendors use a recognizable structure (an
errorobject with atypeorcode). If the body matches the vendor's documented shape, suspect upstream. - Request ID / trace headers — aggregators commonly return their own request ID and may also pass through a vendor request ID. Presence of a vendor-style ID suggests the request reached the vendor.
x-headers — routing, region, or upstream headers often reveal which layer produced the response.- Message text — a message naming your key, balance, or aggregator account points to the gateway; one naming a model, org, or vendor quota points upstream.
401 Unauthorized
- Gateway-produced — your aggregator API key is missing, malformed, or revoked. The request never left the aggregator.
- Upstream-produced — the aggregator's credential with the vendor is invalid or misconfigured. This is not something you can fix by changing your key.
Debug step: if the key works for other models but fails for one vendor, suspect upstream credential/routing issues and check the response body for vendor-specific wording. If every model fails, rotate or re-check your aggregator key.
403 Forbidden
- Gateway-produced — your account is blocked, the model is not enabled for your tier, or an access policy denied the route.
- Upstream-produced — the vendor denied access for the requested model, region, or feature (for example, a model the vendor has not enabled for the aggregator's account).
Debug step: confirm the model is available to your account in the aggregator's documentation, then inspect whether the error body references a vendor policy rather than your account.
404 Not Found
- Gateway-produced — a malformed path or an endpoint that does not exist on the aggregator.
- Upstream-produced — the model name is not recognized by the vendor, or a deprecated model was retired.
Debug step: verify the model identifier against current aggregator docs. If it matches, the vendor may have retired or renamed it; a 404 with a vendor-style body is the tell.
422 Unprocessable Entity
The line is fuzzier here, and both layers can pre-validate.
- Gateway-produced — schema checks on the request body before forwarding (missing fields, malformed JSON, unsupported parameters).
- Upstream-produced — the vendor rejected content after receiving it, such as an invalid message role sequence or a parameter the model does not accept.
Debug step: reduce the request to a minimal, known-good payload and add fields back one at a time. If the minimal request succeeds, the issue is in the payload shape, not routing. A vendor-shaped error body confirms the request was forwarded.
429 Too Many Requests
This is the most commonly misattributed code.
- Gateway-produced — your aggregator key exceeded its own request or concurrency limits.
- Upstream-produced — the aggregator's shared capacity for a vendor is throttled, so your request was rejected after forwarding.
Debug step: look at Retry-After or equivalent headers and compare behavior across models. If only one vendor's models return 429, suspect upstream capacity. If all models do, suspect the aggregator or your own key. Either way, back off with jittered retries rather than retrying immediately.
500 and 502/503/504
- Gateway-produced 500 — an internal aggregator fault, often before forwarding.
- Upstream 500 — the vendor failed while processing the request.
- 502/503/504 — typically a gateway reporting an upstream failure or timeout. These are strong signals the request crossed the aggregator boundary and the upstream (or the connection to it) was the problem.
Debug step: retry idempotent requests with exponential backoff. If the failure is model-specific, it is likely upstream; if it is request-agnostic, the gateway is the better suspect.
A quick triage order
- Check the error body shape and any request ID headers.
- Compare the same request against another model or vendor.
- Re-test with a minimal payload.
- Read
Retry-Afterand timing before retrying. - Escalate with the request ID so the layer that returned the error can be identified from logs.
Treat status codes as hints about a layer, not proof of one. Combining the body, headers, and cross-model comparison gives you a reliable attribution before you change code or contact support.