Skip to content

Errors & rate limits

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.

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).

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.

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.

  • 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-After on 429.