Skip to content

Gateway · For developers · MIT

Debug a Gateway 400, 402 or 429

Diagnose a Lobstack Gateway failure from its status and error class and decide whether retrying can possibly help.

Installing a skill

When an agent loads it

Use when a call returns 400, 401, 402, 403, 429 or 5xx, when a stream ends in an error frame, or when someone reports that the Gateway is broken.

Inside the file

  • The six classes
  • auth — 401, 403
  • quota — 402 and 429 are opposite advice
  • validation — 400
  • provider — 502, 503, 5xx
  • timeout — 408, 504
  • Failures inside a stream
  • Counting them
  • Triage in one pass

The file

v1.0.0
# In Lobstack: Skills › Add a skill, then paste the file or drop the folder
# In Claude Code:
mkdir -p .claude/skills/lobstack-gateway-errors
# paste SKILL.md into .claude/skills/lobstack-gateway-errors/SKILL.md
lobstack-gateway-errors/SKILL.md180 lines
---name: lobstack-gateway-errorsdescription: "Diagnose a Lobstack Gateway failure from its status and error class and decide whether retrying can possibly help. Use when a call returns 400, 401, 402, 403, 429 or 5xx, when a stream ends in an error frame, or when someone reports that the Gateway is broken."license: MITmetadata:  title: "Debug a Gateway 400, 402 or 429"  version: 1.0.0  author: lobstack  category: gateway  tags: [gateway, errors, retries, debugging]--- # Debug a Gateway 400, 402 or 429 Every failure has the same shape, and the type field is the whole diagnosis: ```json{ "error": { "message": "…", "type": "quota", "code": 402,             "request_id": "8f2b1e0c-4d5a-4b91-9c3e-6a7f0d2b5c41" } }``` When there is a machine-readable reason the error also carries an error_codestring: RATE_LIMITED, CLIENT_BUDGET_EXHAUSTED, CLIENT_TAG_INVALID,INVALID_PARAMETER, or the provider's own code. code stays the HTTP status. request_id is also returned as x-lobstack-request-id, on every responseincluding ones that fail before authentication finishes. It is the id of the tracerow, which holds the status, the latency, the model, the credential and the first1,000 characters of the provider's message. Quote it and a description becomes alookup; lose it and you are guessing. ## The six classes | type | status | whose problem | retry || --- | --- | --- | --- || `auth` | 401, 403 | the credential | never || `quota` | 402, 429 | allowance or rate limit | 402 no, 429 yes || `validation` | 400, 409, 422 | the request body | never || `provider` | 502, 503, other 5xx | the upstream provider | yes, with backoff || `timeout` | 408, 504 | we gave up waiting | yes, carefully || `internal` | 500 | ours | once, then report the id | An unrecognised throw is classified internal, not provider — blamingupstream for our own crashes would make the error rate look better than it is. Sointernal really does mean a Lobstack bug. ## auth — 401, 403 Causes, in the order they actually occur: no bearer token; a key that does notmatch lsk_<env>_<8 hex><48 hex>; a key that is unknown, revoked or expired; akey without the inference scope; an agent credential whose machine is notrunning, which returns 403 with the machine status in the message. Revoked and expired are reported distinctly from unknown, because "this key wasrevoked" beats "unauthorized" at two in the morning. All of them are rejections:never retry. The 401 that is not about your key. If the message reads like missingcredentials and the key is definitely good, check the host. The bare apex 307s tothe www host, and RFC 9110 requires every HTTP client to drop theAuthorization header when a redirect changes host. Usehttps://www.lobstack.ai/api/gateway/v1. ## quota — 402 and 429 are opposite advice 402 — the allowance for the period is gone. retry-after is present and iscomputed from the period reset, so it is usually days. It means "this will notclear on its own before then", not "back off". Top up, upgrade, or wait for thereset. Read x-lobstack-quota-meter first: spend carries dollar headers,requests and legacy carry integer ones, and the absent set is absentdeliberately so a client cannot read a missing header as zero allowance. A 402 with error_code: "CLIENT_BUDGET_EXHAUSTED" is a client tag's own budgetwith a hard stop, not the plan's allowance. Raise the budget or turn off the hardstop in the Console under Clients. 429 — a rate limit. Either the Gateway's own, 120 requests a minute per APIkey, with error_code: "RATE_LIMITED" and a retry-after in seconds; or theprovider's, passed through with its status. Back off exponentially with jitterand retry. Every credential is enforced, API keys and legacy agent credentials alike. ## validation — 400 It will fail identically until the body changes. Causes: messages missing orempty; a body that is not JSON; a model key the registry does not know, includingafter alias resolution; a model that exists but is not available in managed mode;BYOK mode with no key on the agent; a malformed passthrough parameter such as atop_p outside 0–1 (error_code: "INVALID_PARAMETER", naming it); amalformed client tag (error_code: "CLIENT_TAG_INVALID"). Provider 400s also land here, with the provider's own message inside — whichmeans a validation error can be about something you never wrote. ### The worked example: the temperature 400 Anthropic deprecated the sampling parameters on Opus 4.7 and everything after it,including Opus 5, Sonnet 5 and the Fable line. The API does not ignore atemperature on those models. It returns: ```json400 {"type":"invalid_request_error","message":"`temperature` is deprecated for this model."}``` This was the most common failure in this Gateway's history, and not becausecallers were setting temperatures: the Gateway itself sent temperature: 0.7 onevery Anthropic request whether or not anyone asked for one, and every single onefailed — for months, while almost no inference ran and nobody could see why. Both halves are fixed. A temperature is forwarded only when the caller set one,and only to models that still accept it, matched on the provider-native id thatgoes on the wire. When one is dropped you getx-lobstack-dropped-params: temperature and a successful response. So if you see this 400 today, you sent a temperature to a model that rejects itthrough a path that is not this Gateway. Find that path — seeaudit-unmetered-model-calls. ## provider — 502, 503, 5xx The upstream failed and it is not your fault. The network call threw (502), theprovider returned a 5xx (passed through with its status), or no managed providerkey is configured on the deployment (503). A provider 401 is deliberately remapped to 502: Lobstack's own credential beingwrong is our failure, and reporting it as 401 would send you to check a key thatis fine. The remap also applies to a call on your own provider key, so a 502there can mean the provider refused your key. Retry with exponential backoff and jitter — except the 503 whose message says noAI provider is available to this key. That one is configuration and will failuntil a key is added: on a paid plan, your own in Settings › Provider keys. ## timeout — 408, 504 Provider calls abort at 120 seconds by default; the route allows up to 300.Anything whose message looks like an abort or a timeout lands here even when itarrives as an unrecognised throw. There is no idempotency key. A request that timed out may have completed at theprovider, so an automatic retry can produce a second answer and a second charge —both metered, because the tokens were really generated. For anything expensive,read the trace by request id before retrying rather than retrying blind. ## Failures inside a stream A stream that fails part-way through cannot change its status: it is already 200and the headers are long gone. The Gateway sends an error object into the streamand then [DONE]: ```data: {"error":{"message":"provider error 529: overloaded","type":"provider","code":529,       "error_code":"overloaded_error","request_id":"8f2b1e0c-…"}} data: [DONE]``` Inside the stream the error has the same fields as any Gateway error: the class astype, and error_code when there is one. **A client that only checks the HTTPstatus will record this stream as a success** — check for an error key on everyframe. ## Counting them GET /api/v1/usage returns summary.errors_by_class over any range, which isthe fastest way to answer "was that bad hour upstream or ours". A failed round alsowrites a ledger row with zero tokens, so error rate is computable from the ledgeralone. See lobstack-usage-reporting. ## Triage in one pass 1. Pull request_id out of the response or the headers. Log it.2. Read type. It tells you whose problem it is before you read the message.3. auth or validation → fix the call. Retrying is guaranteed to fail.4. quota → check x-lobstack-quota-meter; 402 top up, 429 back off.5. provider or timeout → back off and retry, and remember there is no   idempotency key.6. internal → retry once, then report the request id.

More for developers

5
  • Cost

    Read a Lobstack receipt

    Read the receipt Lobstack returns on every model call — cost_usd, savings_usd, baseline_reason — and report cost from it instead of estimating.

  • Migration

    Migrate an SDK call to the Gateway

    Move existing OpenAI or Anthropic SDK code onto the Lobstack Gateway by changing the base URL and the key, and verify it actually routed.

  • Cost

    Pick a model tier, not a flagship

    Choose the cheapest model tier that can actually do the task instead of defaulting to a flagship, and verify the choice before spending on it.

  • Cost

    Keep an agent inside a budget

    Hold an agent, job or run inside a hard dollar budget using the per-call cost the Gateway returns, and handle the 402 when an allowance runs out.

  • Cost

    Write a cost-aware system prompt

    Write or review a system prompt that does not quietly multiply the bill — bounded output, no re-sent bulk, tool schemas counted as the input tokens they are.

All developer skills →