Every API error arrives in one format: a machine error.code, a next step in error.action, the request id request_id (also in the request-id header) and a [code · req_…] tail at the end of error.message itself. The message text is in Russian; the code and the tail are language-neutral. The tail alone is enough for support @Guard_AI_support: it identifies the status, the code and the failing spot. Do not send the full key, the prompt or the answer.
The envelope depends on the endpoint; the error object inside is the same. /v1/messages and count_tokens answer in the Anthropic shape:
{
"type": "error",
"error": {
"type": "billing_error",
"message": "На API-ключе закончился баланс. Пополните ключ в @subscribe_ai_bot и повторите запрос. [insufficient_credit · req_3f9a2c1e8b7d4e0fa1b2c3d4e5f60718]",
"code": "insufficient_credit",
"param": null,
"action": "Пополните ключ в @subscribe_ai_bot либо уменьшите максимальный размер ответа."
},
"request_id": "req_3f9a2c1e8b7d4e0fa1b2c3d4e5f60718"
}/v1/chat/completions and /v1/responses answer in the OpenAI shape without the outer type:
{
"error": {
"message": "На API-ключе закончился баланс. Пополните ключ в @subscribe_ai_bot и повторите запрос. [insufficient_credit · req_3f9a2c1e8b7d4e0fa1b2c3d4e5f60718]",
"type": "billing_error",
"param": null,
"code": "insufficient_credit",
"action": "Пополните ключ в @subscribe_ai_bot либо уменьшите максимальный размер ответа."
},
"request_id": "req_3f9a2c1e8b7d4e0fa1b2c3d4e5f60718"
}Authentication, Usage API and Files API errors put the same object under detail.error (authentication also mirrors it under error). Read error; if it is absent, read detail.error.
| Field | What it holds |
|---|---|
message | the human text (Russian); it ends with the [code · request_id] tail |
code | a stable machine code: branch on it and quote it to support |
type | the error class in Anthropic/OpenAI terms: invalid_request_error, authentication_error, rate_limit_error, api_error, etc. |
param | the field name when the error is about one field, otherwise null |
action | one next step in plain words |
request_id | the request id req_…; the same value is in the request-id header (for Kimi on Chat/Responses also in x-request-id) |
If the failure happens after the SSE stream started, the HTTP status is already 200 and the error arrives as a frame with the same object: an event: error on /v1/messages and /v1/responses, a data: {"error": …} frame followed by data: [DONE] on /v1/chat/completions. The connection is never dropped without a frame, including Kimi, Composer and Grok.
event: error
data: {"type": "error", "error": {"type": "api_error", "message": "Kimi временно недоступен. Повторите запрос через несколько секунд. [kimi_unavailable · req_3f9a2c1e8b7d4e0fa1b2c3d4e5f60718]", "code": "kimi_unavailable", "param": null, "action": "Повторите запрос позже; если ошибка сохраняется, обратитесь в поддержку."}, "request_id": "req_3f9a2c1e8b7d4e0fa1b2c3d4e5f60718"}
# on /v1/chat/completions the same object arrives as
data: {"error": {...}, "request_id": "req_3f9a2c1e8b7d4e0fa1b2c3d4e5f60718"}
data: [DONE]| Code | Meaning | What to do |
|---|---|---|
400 | Bad request (body/params) | Read error.code and param; check the JSON, the model name, required fields (max_tokens for Anthropic). |
401 | Missing, invalid or revoked key | Check the key; issue a new one in the bot. |
402 | Credit exhausted or insufficient for the reserve | Top up the active key or lower max_tokens. |
403 | Operation unavailable for the key or client | Read error.code and the selected API limits; topping up does not resolve every 403. |
404 | Endpoint or model not found | Check the endpoint (/v1/messages, /v1/chat/completions, /v1/responses) and the model id. |
413 | The request body is too large | Reduce the text, attachments or number of messages. |
422 | Parameters failed validation (usage, files) | Fix the field named in param. |
429 | Rate/capacity or spend cap | Read error.code and Retry-After: change a spend cap in the bot; retry temporary limits after a delay. |
500 / 502 | Internal failure or an invalid provider response | Retry; if it persists, send the [code · req_…] tail to support. |
503 | Service temporarily unavailable | Retry with exponential backoff; do not change the model blindly. |
504 | The service did not finish in time | Retry; for long responses use streaming. |
error.code | Status | Meaning | What to do |
|---|---|---|---|
missing_api_key | 401 | no key was sent | send Authorization: Bearer gd-… or x-api-key |
invalid_api_key | 401 | the key is unknown or copied incompletely | copy the key from the bot again |
api_key_revoked, api_key_expired | 401 / 403 | the key was revoked or expired | issue a new key in the bot |
api_key_suspended | 429 | the key is temporarily frozen by a safety rule | wait for the time in Retry-After |
insufficient_credit | 402 | the key's credit is exhausted | top up the key in the bot |
request_reserve_exceeds_credit | 402 | the remaining credit does not cover this request's maximum cost | lower max_tokens or top up |
daily_spend_limit, hourly_spend_limit, daily_reserve_limit, hourly_reserve_limit | 429 | your own spend cap on the key | change the cap in the bot or wait for the window in Retry-After |
invalid_json, invalid_body_type | 400 | the body is not JSON or not an object | fix the request body |
invalid_request, unsupported_parameter, invalid_parameter | 400 | a field is invalid or unsupported on this surface; the name is in param | remove or fix the field |
messages_required, model_required | 400 | a required field is missing | add the field |
model_not_found | 404 | no such model in the catalogue | take an id from GET /v1/models |
route_not_found, method_not_allowed | 404 / 405 | no such path or method | check the endpoint and method |
request_body_too_large | 413 | the body exceeds the limit | reduce the text or attachments |
context_length_exceeded | 400 | the request does not fit the model's context window | shorten the history or pick a model with a larger window |
product_modes_removed | 410 | Product modes are removed; an obsolete mode filter was sent | Remove mode from the Usage API request |
cyber_refusal | 400 / stream error | Claude returned a structured cybersecurity refusal | Change the wording or contact support |
client_key_rate_limit, client_ip_rate_limit | 429 | too frequent from one key or address | retry after Retry-After |
service_capacity_saturated, standard_capacity_saturated | 429 | all service slots are busy | retry after Retry-After |
service_unavailable, upstream_unavailable | 503 | the service or provider is temporarily down | retry with exponential backoff |
stream_service_error, stream_timeout | in the stream | a failure after the stream started | retry; reduce the context on retry |
internal_error | 500 | an internal service failure | send the [code · req_…] tail to support |
usage_rate_limit, invalid_cursor | 429 / 400 | Usage reads are too frequent or the cursor is invalid | See Usage API |
Kimi codes, including files, search and the seven reasons for 429, live on Kimi · Errors and retry. Composer and Grok codes follow.
Composer/Grok have their own error.code values. A new request rejected locally before contacting the model is not billed. An error during an existing tool loop or stream can concern work already executed and billed; check request history.
error.code | Status | What it means |
|---|---|---|
cursor_parameter_unavailable | 400 | the body carries a field outside the short accepted list |
cursor_client_tools_unavailable | 400 | the Responses input carries a provider-hosted tool item — web_search_call, file_search_call, computer_call and the like |
cursor_client_tools_invalid | 400 | a bad tool declaration: more than 64 of them, a duplicate or invalid name, a schema over 256 KiB |
cursor_client_tool_result_invalid, cursor_client_tool_result_too_large, cursor_client_tool_result_unsupported | 400 | the tool result is malformed, over 8 MiB, or in an unsupported shape |
cursor_image_input_unavailable | 400 | an image was sent to Composer, which does not take them |
cursor_image_input_invalid | 400 | the picture is not inline base64, has an unsupported type, or there are more than 16 |
model_not_found | 404 | the id is misspelled |
request_reserve_exceeds_credit | 402 | the key balance does not cover the reserve for this request |
cursor_daily_spend_limit, cursor_hourly_spend_limit, cursor_daily_reserve_limit, cursor_hourly_reserve_limit | 429 | your own spend limit; Retry-After carries the window length |
client_key_rate_limit | 429 | too frequent; retry after a short pause |
cursor_key_pause_limit | 429 | The key has reached its unfinished-tool-loop limit. Finish an existing loop; retrying alone will not help. |
cursor_model_mismatch | in stream | a different model answered upstream; arrives as a separate error event |
cursor_unavailable | 503 | temporary unavailability; retry with exponential backoff |
cursor_run_timeout | 504, an error event in a stream | the run did not finish within 600 seconds and was cancelled. The run is paid for |
cursor_output_limit_exceeded | 502 for non-streaming replies | The whole loop exceeded its output limit; executed work is billed. Streaming retains text and ends with max_tokens / length / response.incomplete. |
cursor_upstream_error | 502, an error event in a stream | the run did not complete upstream. If the answer had already started, it is paid for |
- The
[code · req_…]tail from the message text or therequest_idvalue — a screenshot is enough. - Endpoint, model,
streamtrue/false and the time with its zone. - No full key, prompt or model answer.