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_help: 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-ключе закончился баланс. Пополните ключ в @guardapi и повторите запрос. [insufficient_credit · req_3f9a2c1e8b7d4e0fa1b2c3d4e5f60718]",
"code": "insufficient_credit",
"param": null,
"action": "Пополните ключ в @guardapi либо уменьшите максимальный размер ответа."
},
"request_id": "req_3f9a2c1e8b7d4e0fa1b2c3d4e5f60718"
}/v1/chat/completions and /v1/responses answer in the OpenAI shape without the outer type:
{
"error": {
"message": "На API-ключе закончился баланс. Пополните ключ в @guardapi и повторите запрос. [insufficient_credit · req_3f9a2c1e8b7d4e0fa1b2c3d4e5f60718]",
"type": "billing_error",
"param": null,
"code": "insufficient_credit",
"action": "Пополните ключ в @guardapi либо уменьшите максимальный размер ответа."
},
"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.
Messages returns an Anthropic-compatible wrapper; Chat and Responses use an OpenAI-compatible wrapper. Branch on HTTP status and error.code, not localized message text.
{
"error": {
"message": "…",
"type": "invalid_request_error",
"code": "unsupported_media",
"param": "messages"
}
}| Group | Codes |
|---|---|
| Fix request | invalid_json, invalid_request, invalid_parameter, unsupported_media, unsupported_parameter, unsupported_tool, model_not_found |
| Retry with delay | client_key_rate_limit, glm_queue_timeout, glm_rate_limit, glm_unavailable |
| Responses continuation | response_not_found, response_account_unavailable |
| Malformed upstream response | glm_invalid_response, glm_invalid_stream, glm_count_unavailable |
See GLM: errors and boundaries for the full action table, including the 10-second queue, Retry-After, media, and previous_response_id.
Gemini errors use the same wrapper as the other families: branch on the HTTP status and error.code, not on the text. In Chat Completions and Responses error.param names the field when it is known; in Messages it is always null. A request refused before it reaches the model is not charged.
error.code | Status | Meaning | What to do |
|---|---|---|---|
invalid_json, invalid_request | 400 | the body is not JSON or a field is invalid, including a reasoning level the model does not have; the field name is in param | fix the request body |
model_not_found | 404 | no such model in the catalog | take the id from GET /v1/models: gemini-4-argon or gemini-3.8-flash |
gemini_parameter_unsupported | 400 | a field Gemini does not support; param names the object that holds it, and "request" for a top-level field | remove the field |
gemini_unsupported_content, gemini_media_unsupported | 400 | Gemini accepts text, images, and PDF; audio, video, and other files are not accepted | remove the attachment or send its content as text |
gemini_invalid_media, gemini_inline_media_required | 400 | the attachment is invalid: the link is not https or contains a login, or the base64 is damaged; in Messages the source is neither base64 nor a link; an image link inside a tool result | send the attachment as base64 or an open https link; inside a tool result, as base64 |
gemini_tool_result_media_unsupported | 400 | a tool result contains an attachment other than PNG, JPEG, WEBP, or PDF | send the result as text or in one of these formats |
gemini_tool_unsupported | 400 | a tool other than functions and search, for example separate page loading web_fetch | keep functions and the built-in search |
gemini_search_options_unsupported | 400 | a search setting Gemini does not have: a domain list, max_tool_calls, and other fields | keep only type, name, and max_uses on the search tool |
gemini_tool_choice_unsupported | 400 | a required call or a call of a specific function combined with search, or a required call without functions | split the request or remove the required call |
gemini_strict_tools_unsupported, gemini_parallel_limit_unsupported | 400 | strict: true on a function or a ban on parallel calls | remove the field |
invalid_tool_structure | 400 | duplicate function names, a tool_choice naming a function that is not in the list, call arguments that are not JSON, or a function call outside an assistant message | fix the function list or the call history |
gemini_thinking_unsupported | 400 | a thinking form Gemini does not accept: budget_tokens, other thinking or reasoning fields, reasoning.summary other than "auto" | use thinking: {"type": "adaptive"} and set the level with the level field from the model page |
invalid_request with param: "background" | 400 | background Responses execution is not supported | remove background |
gemini_history_required | 400 | Gemini does not accept the conversation field | send the history in input or continue with previous_response_id |
gemini_history_mismatch, gemini_native_history_invalid, gemini_history_not_found | 400 / 404 | the history does not match the saved one, the saved history of a function call does not fit the request, or the response for previous_response_id was not found or is older than 30 days | send the whole dialogue history |
gemini_rejected | 400 | Gemini did not accept the request | check the request fields and the dialogue history |
policy_refusal | 400 | Google refused the request or the answer under its own rules: a block, safety, or a match with protected text. This code comes only without streaming: a stream gets 502 gemini_invalid_stream before the answer starts and a gemini_stream_error frame after | rephrase the request |
api_key_paused | 403 | the key or this family is paused in the key settings | resume the key or turn the family on in the key settings in your Guard account |
insufficient_credit, request_reserve_exceeds_credit | 402 | the key balance is used up or does not cover the request reserve | top up the key in the bot or lower max_tokens |
client_key_rate_limit, gemini_rate_limited | 429 | too many requests from one key, or Gemini temporarily limited the request rate | retry after Retry-After |
gemini_quota_exhausted | 429 | the quota of this model is used up | retry after the limit resets (time in Retry-After) or choose another model |
gemini_unavailable, service_unavailable | 503 | no free account right now, or Gemini is temporarily unavailable | retry with exponential backoff |
gemini_not_connected | 503 | Gemini models are not connected yet | retry later or choose a model of another family |
gemini_settings_unavailable, gemini_billing_unavailable, gemini_history_unavailable | 503 | settings, accounting, or the history store is temporarily unavailable | retry in a few seconds |
gemini_invalid_response, gemini_invalid_stream, gemini_invalid_usage, gemini_incomplete_response, gemini_incomplete_stream, gemini_empty_response, gemini_generation_failed, gemini_unsupported_output, gemini_partial_function_call_unsupported, gemini_invalid_json_value, gemini_upstream_error | 502 | the Gemini response came incomplete or invalid | a new request is safe only if your application prevents duplicate side effects |
gemini_stream_error | in the stream | the stream broke after the answer started. Internal failures parsing the Google stream (gemini_stream_event_too_large, gemini_stream_already_finished) arrive as this frame, and before the answer starts as 502 gemini_invalid_stream | the delivered part stays with the client; retry the request |
Muse errors use the same wrapper as the other families: branch on the HTTP status and error.code, not on the text. In Chat Completions and Responses error.param names the field when it is known; in Messages it is always null. A request refused before it reaches the model is not charged.
error.code | Status | Meaning | What to do |
|---|---|---|---|
invalid_json, invalid_request | 400 | the body is not JSON, a field is invalid, or Meta refused the request parameters | fix the request body |
invalid_parameter, invalid_messages, invalid_input, invalid_stream, invalid_stream_options, invalid_tools, invalid_previous_response_id | 400 | a field value is invalid, for example the level none or a non-boolean store; the field name is in param | fix the field |
unsupported_parameter | 400 | a field Muse does not support: a separate web_fetch, search domain limits, background Responses execution, token counting with previous_response_id | remove the field; for counting, send the history in input |
unsupported_media | 400 | Muse accepts text, images, and PDF; video, audio, and other files are not accepted | remove the attachment or send its content as text |
unsupported_tool | 400 | provider-side MCP tools are not available through Guard | remove the tool or run it as a client function |
model_not_found | 404 | no such model in the catalog | take the id from GET /v1/models |
response_not_found | 404 | this key has no response for previous_response_id, or it was created with store: false | send the history in input |
response_account_unavailable | 409 | the continuation is temporarily unavailable on the account that stores the response | retry later or send the history in input |
api_key_paused | 403 | the key or this family is paused in the key settings | resume the key or turn the family on in the key settings in your Guard account |
insufficient_credit, request_reserve_exceeds_credit | 402 | the key balance is used up or does not cover the request reserve | top up the key in the bot or lower max_tokens |
client_key_rate_limit, muse_rate_limit, muse_queue_timeout | 429 | too many requests from one key, or all Muse slots are busy | retry after Retry-After |
muse_unavailable, muse_pool_unavailable | 503 | Muse is temporarily unavailable | retry with exponential backoff |
muse_not_connected | 503 | Muse models are not connected yet | retry later or choose a model of another family |
muse_prompt_unavailable, muse_state_unavailable, muse_billing_unavailable | 503 | settings, response state, or accounting is temporarily unavailable | retry in a few seconds |
muse_prompt_model_invalid | 503 | an applied Muse setting contains an invalid request change | do not loop the same request; send the code to support |
muse_invalid_response, muse_invalid_stream | 502 | the Meta response came incomplete | a new request is safe only if your application prevents duplicate side effects |
muse_stream_error | in the stream | the stream broke after the answer started | the delivered part stays with the client; retry the request |