Ошибки и лимиты

Формат ошибок, HTTP-коды, коды ошибок по категориям, заголовки лимитов и retry-логика.

Ошибки

Формат ошибки

OpenAI-совместимый API (/v1/chat/completions и /v1/models) отвечает на любую ошибку одним объектом. Тот же объект приходит последним кадром потока, если ход упал после начала стрима.

json
{ "type": "error", "error": { "type": "invalid_request_error", "code": "DATA_INVALID_PARAMETER", "message": "Invalid request parameter body.messages: Field required", "param": "body.messages" }, "request_id": "76a9e461-7848-4159-b90f-5c0d704ac97f" }
ПолеТипОписание
error.typestringСемейство ошибки: invalid_request_error, authentication_error, permission_error, not_found_error, billing_error, rate_limit_error, api_error, overloaded_error. Ветвитесь по нему
error.codestringСтабильный машиночитаемый код, строка таблицы ниже. Для подробностей ветвитесь по нему, а не по тексту
error.messagestringТекст на английском
error.paramstring | nullПоле запроса, к которому относится ошибка (body.messages, model, session_id)
request_idstring | nullТо же значение, что заголовок x-request-id

Семейство следует за статусом: 400 и 422 это invalid_request_error, 401 это authentication_error, 402 это billing_error, 403 это permission_error, 404 это not_found_error, 409 это invalid_request_error, 429 это rate_limit_error, 503 это overloaded_error, прочие 5xx это api_error. Признака повтора в теле нет: повторяйте по статусу и заголовку Retry-After (см. Повторные попытки). Прокси могут вернуть не-JSON; проверяйте форму ответа перед чтением полей.

Конверт detail. Другой формой, {"detail": {"code", "message", "message_en", "hint", "is_retryable", …}}, отвечают два места: 401 MCP-сервера, который приходит до чтения MCP-сообщения, и нативный /api/v1 (управление ключами, см. Аутентификация). Там message по-русски, message_en по-английски, а путь к полю при ошибке схемы в field.

Ошибки инструментов MCP

Инструменты, вызываемые через MCP (например, connector_execute), не используют HTTP-коды. Неудачный вызов возвращает результат с isError: true, текст которого несёт JSON-объект {code, message, retryable, hint?, details?}; hint и details приходят, когда есть. MCP SDK может добавить перед текстом префикс Error executing tool …:, поэтому разбирайте JSON после него:

json
{ "code": "SERVICE_RATE_LIMITED", "message": "External service rate limit exceeded.", "retryable": true }

Если retryable равно true, вызов можно повторить после небольшой задержки; если false, повтор с теми же аргументами снова завершится ошибкой.

HTTP-коды ответов

КодОписание
200Success
201Created: ресурс создан
202Принято: ход допущен и выполняется в фоне
204No Content: успешное удаление
400Bad Request: неверные параметры или тело запроса
401Unauthorized: отсутствует или недействителен токен
402Payment Required: недельный лимит исчерпан или нужен тариф. Повтор до reset_at не поможет
403Forbidden: нет доступа к ресурсу или у ключа нет нужного scope
404Not Found: ресурс не существует или недоступен вам (эти случаи не различаются)
409Conflict: состояние ресурса не допускает операцию (например, в чате уже идёт ход или session_id принадлежит другому агенту) или ключ идемпотентности занят другим запросом
413Content Too Large: файл или тело больше допустимого
422Unprocessable Entity: тело не прошло схему; путь к полю в error.param на /v1, в field/fields на нативном API
429Too Many Requests: превышен лимит частоты или число одновременных чатов
500Internal Server Error
502, 503Сбой внешнего сервиса или временная недоступность; повторяйте с паузой
504Gateway Timeout: запрос выполнялся слишком долго

Коды ошибок

Коды, которые может получить клиент /v1 и MCP, со статусом, текстом и признаком повтора, которыми отвечает сервер. Список кодов растёт: незнакомый код обрабатывайте по HTTP-статусу и error.type, а не падением клиента.

HTTPКодЗначениеПовтор
400DATA_INVALID_PARAMETERПередан некорректный параметр запроса.нет
400TOOL_VALIDATION_FAILEDВ запросе не хватает данных или они в неверном формате.да
400UNKNOWN_INSTANCEКабинет не выбран или не найден. Выберите из доступных.нет
401AUTH_HEADER_MISSINGОтсутствует заголовок авторизации.нет
401AUTH_INVALID_CREDENTIALSНе удалось подтвердить вход. Попробуйте ещё раз.нет
401AUTH_TOKEN_EXPIREDСрок действия токена истёк.нет
401AUTH_TOKEN_INVALIDНедействительный токен авторизации.нет
402DATA_USAGE_QUOTA_EXCEEDEDНедельный лимит исчерпан. Он обновится автоматически.нет
402SUBSCRIPTION_REQUIREDДля этого нужен подходящий тариф.нет
403APPROVAL_NOT_ASKABLEЗапись требует одобрения, а отсюда его не спросить: она не выполнена.нет
403AUTH_PERMISSION_DENIEDНедостаточно прав для выполнения операции.нет
403AUTH_SCOPE_MISSINGИнтеграция не имеет нужного доступа для этого действия. Переподключите её с расширенными правами.нет
403AUTH_SCOPE_NOT_GRANTABLEСервис отказал в этом действии, форма подключения доступ к нему не откроет.нет
403TOOL_AUTO_REVIEW_BLOCKEDДействие остановлено автопроверкой.нет
404DATA_NOT_FOUNDЗапрошенный ресурс не найден.нет
409AGENT_ON_A_CALLАгент сейчас в другом разговоре. Дождитесь его конца и начните снова.да
409DATA_CONFLICTДействие конфликтует с текущим состоянием данных или работы.нет
409SESSION_BUSYВ этом чате ещё идёт ход. Дождитесь ответа или остановите его и повторите.да
409WRITE_OUTCOME_UNKNOWNИсход записи неизвестен: сервис мог её принять. Повторно она не отправлена.нет
429LLM_RATE_LIMITEDПревышен лимит запросов. Подождите немного.да
429RATE_LIMIT_EXCEEDEDСлишком много запросов. Подождите немного.да
429SERVICE_RATE_LIMITEDЗапросы к внешнему сервису временно ограничены. Попробуйте позже.да
429SESSION_CONCURRENCY_LIMITСлишком много активных чатов. Закройте неиспользуемые и попробуйте снова.да
500DATABASE_QUERY_CANCELEDСервер базы данных прервал запрос. Если ошибка повторяется, напишите в поддержку.нет
500SERVICE_SERVER_ERRORЧто-то пошло не так. Попробуйте ещё раз чуть позже.да
502LLM_PROVIDER_ERRORМодель не ответила. Попробуйте ещё раз.да
503DATABASE_UNAVAILABLEСервис временно недоступен. Ждём восстановления соединения с базой.да
503LLM_PROVIDER_UNAVAILABLEМодель временно недоступна. Попробуйте через несколько минут.да
503SERVICE_UNAVAILABLEСервис временно недоступен. Попробуйте позже.да
504LLM_REQUEST_TIMEOUTМодель не ответила вовремя. Попробуйте ещё раз.да

Пример обработки ошибок

Рекомендуемый подход к обработке ошибок API на Python.

python
import requests response = requests.post(url, headers=headers, json=body) if response.status_code >= 400: try: payload = response.json() except ValueError: payload = {} error = (payload.get("error") or payload.get("detail") or {}) if isinstance(payload, dict) else {} if not isinstance(error, dict): error = {"message": str(error)} family = error.get("type") code = error.get("code", f"HTTP_{response.status_code}") message = error.get("message") or response.text request_id = response.headers.get("X-Request-ID") if response.status_code == 429: retry_after = response.headers.get("Retry-After", "60") print(f"Rate limited. Retry after {retry_after}s") elif response.status_code == 401: print(f"Auth error: {message}") else: print(f"Error [{code}] {family}: {message} (param {error.get('param')}, request {request_id})")

ID запроса

Каждый HTTP-ответ, успешный или нет, несёт заголовок X-Request-ID (и X-Trace-ID). Можно передать свой X-Request-ID в запросе, тогда ответ вернёт его же. Прикладывайте этот ID к обращению в поддержку: по нему находится запрос в логах.

Лимиты запросов

Заголовки лимитов

Если отказ знает задержку, он несёт заголовок Retry-After в целых секундах (округление вверх). На /v1 задержка названа только в этом заголовке. Заголовков X-RateLimit-* API не отдаёт: остаток лимита заранее не узнать, ориентируйтесь на 429. Retry-After встречается и у других повторяемых ошибок (409 SESSION_BUSY, 503); клиенту стоит принимать и секунды, и HTTP-дату.

Лимиты по тарифам

Каждый API-ключ организации имеет свой минутный лимит по тарифу организации; один и тот же бюджет тратят /v1/chat/completions, /v1/models и вызовы инструментов MCP.

ТарифЗапросов в минуту на ключ
Pro180
Max360

Лимиты могут меняться; актуальные значения на странице тарифов.

Ответ при превышении лимита

При превышении лимита API возвращает статус 429 и называет паузу в заголовке Retry-After.

http
HTTP/1.1 429 Too Many Requests Retry-After: 12 Content-Type: application/json { "type": "error", "error": { "type": "rate_limit_error", "code": "RATE_LIMIT_EXCEEDED", "message": "Too many requests. Please wait a moment.", "param": null }, "request_id": "0b7d4e2a-6c1f-4a8e-9d3b-2f5a7c1e8b40" }

Недельный лимит

Расход модели считается в недельном окне тарифа (месячного бюджета больше нет). Когда окно исчерпано, /v1/chat/completions и запуск задач отвечают 402 DATA_USAGE_QUOTA_EXCEEDED (тариф без задач отвечает SUBSCRIPTION_REQUIRED с полями feature, required_plans и min_plan). На /v1 это объект ошибки с error.type: "billing_error"; тело detail нативного API несёт ещё usage, limit, percent и reset_at. Retry-After нет: окно обновится само, а повтор до этого снова получит 402.

Повторные попытки

Повторяйте на 429, 502, 503 и 504 (на /v1: error.type равен rate_limit_error, overloaded_error или api_error): ждите Retry-After, а без него используйте экспоненциальную задержку. Прочие 4xx отвечают на сам запрос; на нативном API то же говорит is_retryable. GET/HEAD повторяйте автоматически, мутации вслепую не повторяйте. POST /v1/chat/completions вслепую не повторяйте: повторный запрос запускает ещё один ход. После оборванного потока продолжайте разговор с тем же session_id (см. Стриминг).

python
import time import requests def request_with_retry(url, headers, max_retries=3): for attempt in range(max_retries): response = requests.get(url, headers=headers) if response.status_code in (429, 503): retry_after = int(response.headers.get("Retry-After", str(2 ** attempt))) print(f"Rate limited. Retrying in {retry_after}s...") time.sleep(retry_after) continue return response raise Exception("Max retries exceeded")

Лучшие практики

  • Кэшируйте ответы, которые не меняются часто (например, список моделей)
  • Используйте экспоненциальную задержку при повторных попытках
  • Не повторяйте 402 и прочие 4xx, кроме 429 и SESSION_BUSY: без изменений запрос снова получит отказ
  • Следуйте пагинации конкретного эндпоинта: страницы за вас никто не обходит
Была ли страница полезна?