Telluvian

Errors and rate limits

Status codes, error shapes, and throttling.

Copy this page as Markdown to paste into an AI assistant, or open it in one.

Errors are OpenAI-shaped: a JSON body with an error object carrying message, type, and code. The one exception is 422, covered below.

{
  "error": {
    "message": "Insufficient credits. Top up your balance in the dashboard.",
    "type": "invalid_request_error",
    "code": "insufficient_credits"
  }
}

Status codes

StatusMeaningWhat to do
400Malformed JSON, invalid Model Select controls, or analyze without probe opt-in.Check the body; analyze requires include_scores: true.
400upstream_bad_request: the model provider rejected the request, often a parameter it does not accept or a prompt longer than its context window.Check max_tokens, temperature and the message format.
400byok_credential_rejected: your own provider key was rejected and nothing else could serve the request.Check the key under Provider keys. See Bring your own key.
400credential_not_found / credential_not_usable: the request's byok_credential names no key, or a key that cannot serve this model or this API key.Check the slug under Provider keys, or drop the field to use the default order.
401Missing, unknown, or revoked API key.Check the Authorization header, or mint a new key.
402Balance exhausted, or (byok_credential_rejected) your provider account is out of credit.Add credit, or top up with the provider.
403Account suspended, or the wrong kind of key: a management key on a model endpoint, or an ordinary key on /v1/byok.Contact us, or use the right key.
404Unknown model, or unknown previous_response_id.Call GET /v1/models, or check the id.
413upstream_request_too_large: the request is too large for the model.Shorten the prompt, or use a model with a larger context window.
422Request body failed schema validation: a non-string content, or an -analyze call with no assistant message.Check the shape against Compatibility.
429Rate limited by us, or (upstream_rate_limited) the model is rate-limited by its provider.Back off for Retry-After seconds, or use your own provider key.
502upstream_unavailable: the model provider returned an error. With your own key, byok_credential_rejected.Retry with backoff, or try another model.
503Model Select is unavailable.Retry with backoff, or name a model yourself.
504upstream_timeout: the model provider did not respond in time. With your own key, byok_credential_rejected.Retry with backoff.

A provider failure is always answered in our words, with type: "upstream_error" and one of the upstream_* codes above. The provider's own error text is never passed on.

422 has a different body shape

A 422 comes from the model server's own validation and is relayed unchanged, so it carries {"detail": ...} rather than the error object above. It is a string for the analyze case, and a list of field errors for a schema violation. Nothing is billed for a rejected request.

A 404 for an unrecognised model carries code: "model_not_found" and names the offending field in param:

{
  "error": {
    "message": "The model 'gpt-9' does not exist or you do not have access to it. Call GET /v1/models for the available models, or see https://telluvian.ai/docs.",
    "type": "invalid_request_error",
    "param": "model",
    "code": "model_not_found"
  }
}

Model Select

A Model Select control that cannot be honoured is rejected before anything is generated, and nothing is billed. The message names the field. A direct /v1/modelSelect call returns its own error envelope with a stable code; see Model Select errors. The common causes:

StatusCause
400xPerf sent as a quoted number, or naming a model we do not know.
400xPerfEffort sent alongside a numeric xPerf, or an effort the named model does not offer.
400xLatency outside instant, chat and batch.
400modelZoo matching no active Model Select candidate.
400sessionId that is not a GUID.
503Model Select is unavailable. Nothing is substituted. See when Gallery is unavailable.

A quality bar that nothing can meet is not an error: the request succeeds on the best model available. Read response.model to see what ran.

Rate limits

Chat Completions and Responses normally carry these headers when rate-limit checks complete successfully:

  • X-RateLimit-Limit, requests allowed in the current window
  • X-RateLimit-Remaining, how many are left

A 429 additionally carries Retry-After, in seconds.

Limits are per API key, 600 requests per 60-second window by default. That is generous, because spend is already gated by your balance. It is an abuse ceiling rather than a quota. A rejected request still counts against the window, so hammering the endpoint keeps it pinned rather than earning a fresh allowance. If you need a higher limit, get in touch.

The limiter fails open

Counting happens centrally, not per server instance. The gateway runs on several at once, and an in-process counter on each would both admit multiples of the intended limit and reset every time an instance scales. If that count itself is unreachable (a database blip), the request is allowed through rather than rejected: a limiter that hard-fails every request during a partial outage would turn it into a total one. Your balance is the backstop either way. A burst let through during a blip still has to be paid for.

Balances can dip slightly negative

The balance check happens before your request runs, but the cost is settled after it finishes. A request admitted with a small positive balance can take it just below zero, bounded by your max_tokens. The next request is then refused with a 402.

Streaming failures

A stream can fail after it has already started, after your client has received a 200 and some content chunks. There is no structured SSE error event for this: the connection is simply closed without a trailing data: [DONE].

A stream without [DONE] is a failure, not a slow finish

Treat any stream that ends without the literal data: [DONE] line as failed, not as "still coming." Retry the request rather than waiting.

Billing settles from whatever token counts were observed before the failure (or an estimate when final usage is unavailable), so a request that fails partway through can still incur a (smaller) charge for the tokens the model had already generated, the same way a partial response you kept and used would be billed. This is the same settlement path either way; see Pricing.