Errors & rate limits
Error envelope
Section titled “Error envelope”Errors use a consistent envelope:
{ "error": { "code": "INVALID_API_KEY", "message": "Invalid or revoked API key" } }Anthropic-dialect requests are not uniform: most errors (including auth
failures) use the envelope above, while some Anthropic-shaped errors wrap it as
{ "type": "error", "error": { … } }.
Authentication
lists the auth codes.
Rate limits (429)
Section titled “Rate limits (429)”LunaRoute meters concurrency with lanes, not requests per
second. When your organization is at its lane cap, a request does not
fail immediately — it parks and waits for a free lane (up to 60 seconds for
interactive work). You get a 429 only if the queue is full or the park
deadline expires. Both cases return the same 429 with Retry-After.
Other 429s come from capacity further down the stack, not your lane cap:
embedding_gateway_busy and embedding_backend_busy mean the embedding gateway
or backend is overloaded. Treat them the same way — back off and retry.
Every 429 carries a Retry-After header telling you how long to back off
before retrying:
| Surface | error.code |
Retry-After |
|---|---|---|
| Chat, Messages, Responses | CONCURRENT_REQUEST_LIMIT_EXCEEDED |
60 |
| Image generation | concurrent_request_limit_exceeded |
60 |
| Embeddings / rerank — org lanes | embedding_lanes_exhausted |
1 |
| Embeddings / rerank — gateway busy | embedding_gateway_busy |
1 |
| Embeddings / rerank — backend overloaded | embedding_backend_busy |
1 |
Image generation shares the interactive lane pool, so a lane refusal there
carries the same flat 60 as chat.
A 409 idempotency_in_progress (image generation) means another attempt with
the same idempotency key is already running; it carries Retry-After set to the
remaining lease (1–60 seconds).
Retryable 5xx
Section titled “Retryable 5xx”Some outages are transient and answer 503 with Retry-After:
| Surface | error.code |
Retry-After |
|---|---|---|
| Image normalization unavailable | image_normalization_unavailable |
30 |
| Embeddings / rerank billing plane | embeddings_billing_unavailable |
— |
Treat 503 as “temporarily unavailable”, not “not found” — feature kill switches
answer 503 <feature>_disabled rather than removing the route.
Upstream provider errors
Section titled “Upstream provider errors”If a model provider rate-limits or refuses a request, the error carries a
cause field, for example:
{ "error": { "code": "…", "message": "…", "cause": "rate_limited" } }Causes are rate_limited, content_policy_violation, and
model_context_length_exceeded. rate_limited means the provider is
throttling — back off and retry, or route to a different provider or model.
content_policy_violation and model_context_length_exceeded need a different
prompt or model. All three are distinct from your own lane cap.
Sizing clients
Section titled “Sizing clients”- Give clients a timeout comfortably above 60 seconds — the interactive park deadline is exactly 60s, so a client that times out at 60s may be racing the gate.
- Keep a parallel worker pool no larger than your interactive lane count, and
honor
Retry-Afteron429.