Error Reference
Stable error codes, categories, retry guidance, and request ID debugging.
Non-success responses use a structured envelope:
{
"error": {
"code": "UPSTREAM_ERROR",
"category": "upstream",
"message": "Underlying provider returned an error.",
"provider": "anthropic",
"model": "claude-sonnet-4-6",
"request_id": "req_abc123",
"retryable": true,
"suggested_action": "retry_with_backoff"
}
}Top-level code, message, and request_id are also present for older SDKs. New integrations should read error.code and error.category.
Categories
| Category | Meaning | Generic handling |
|---|---|---|
auth | LatentKit API key or upstream credential problem | Fix credentials; do not retry blindly. |
billing | Credits or billing state blocks execution | Surface to workspace owner; retry after top-up or plan change. |
policy | Routing policy, guardrail, or request eligibility refused execution | Change policy or request; retries usually repeat the same failure. |
quota | LatentKit or upstream rate limit | Retry idempotent requests with backoff. |
upstream | Provider timeout, 5xx, invalid JSON, or provider-side failure | Retry with exponential backoff; inspect provider/model. |
routing | No healthy eligible route could execute | Check policy, connections, provider health, and model capability. |
gateway | LatentKit deadline or internal failure | Retry transient failures; include request ID with support tickets. |
model_output | Provider returned a syntactically successful but unusable model result | Retry with stricter tool choice, larger token budget, or deterministic fallback. |
Codes
| HTTP | error.code | error.category | Retry? | Meaning |
|---|---|---|---|---|
200 / 503 | TOOL_CALL_NOT_PRODUCED | model_output | Yes | A tool call was required but the model returned text. |
200 / 503 | TRUNCATED_OUTPUT | model_output | Yes | Output ended because the token budget was too small. |
401 | INVALID_API_KEY | auth | No | Missing, invalid, expired, or revoked LatentKit API key. |
402 | INSUFFICIENT_CREDITS | billing | No | Workspace lacks Platform Access credits or budget. |
403 | POLICY_REJECTED | policy | No | Guardrail, route policy, or eligibility rejected the request. |
408 | UPSTREAM_TIMEOUT | upstream | Yes | Provider timed out before returning a response. |
429 | RATE_LIMITED | quota | Yes | LatentKit or upstream rate limit was hit. |
502 | UPSTREAM_ERROR | upstream | Yes | Provider returned a failed response or invalid payload. |
503 | NO_HEALTHY_PROVIDER | routing | Yes | No eligible provider/model route was healthy or executable. |
504 | EXECUTION_TIMEOUT | gateway | Yes | LatentKit's end-to-end execution deadline expired. |
Oversized uploads and queue payloads are rejected with the structured envelope (413 for streamed uploads); reduce the payload instead of retrying — see Rate limits.
Backoff guidance
For quota, upstream, routing, and gateway retryable errors, use jittered exponential backoff and cap retries. For model_output, a retry can help, but repeated failures usually mean the prompt, tool_choice, or max_tokens needs to change.
What LatentKit retries for you
Inside a single request, LatentKit only auto-retries transport failures that provably happen before the request reaches the provider (connection establishment). Ambiguous failures — read timeouts and protocol errors after the provider may have accepted the request — are never replayed automatically, because the provider might already have run and billed the generation. They surface as UPSTREAM_TIMEOUT or UPSTREAM_ERROR so your application decides whether a replay is safe.
Route-level failover is separate: when an attempt fails with a retryable provider error, the published policy's next eligible provider/model entry is tried, and you still receive one response.
Debugging with request IDs
Every response should include X-LK-Request-ID; JSON bodies also include error.request_id. Include that ID when contacting support or correlating your app logs with LatentKit request logs.