Ошибки и лимиты
Обновлено
Отказ приходит в одной и той же форме на всех ручках, а по заголовкам ответа видно, сколько запросов осталось и когда повторять. Эта статья описывает то и другое.
Форма отказа
{
"error": {
"code": "cost_above_limit",
"message": "The generation costs more than the maxCredits ceiling in the request.",
"retryable": false,
"details": { "credits": 62, "maxCredits": 40 }
}
}
code — машинный идентификатор, единственное, на что стоит программировать. message написан для человека, читающего лог, и может меняться. retryable отвечает, имеет ли смысл повторить тот же запрос без изменений. details есть не всегда: там лежит машинная диагностика — перечень проблем валидации, незакрытые входы, числа.
Локализации нет: ответ читает программа, а не человек в интерфейсе.
Каждый ответ несёт X-Request-Id. Он же записан в наших логах, поэтому разбор происшествия начинается с одной строки — приложите его к обращению в поддержку.
Коды и статусы
Список закрыт: код, которого нет в таблице, наружу не уходит. Новые значения могут появляться — незнакомый код обрабатывайте по числовому статусу и признаку retryable из ответа.
| Код | HTTP | Когда приходит |
|---|---|---|
access_denied | 403 | Внешний доступ этому счёту закрыт |
account_blocked | 403 | Аккаунт заблокирован |
cancel_conflict | 409 | Состояние генерации изменилось во время отмены |
cost_above_limit | 402 | Запрос дороже переданного maxCredits |
credit_reservation_failed | 402 | Резерв кредитов не удался |
family_not_found | 400 | Такого семейства в каталоге нет |
family_unavailable | 503 | Семейство временно недоступно |
file_fetch_failed | 502 | Файл по ссылке не забрался |
file_metadata_missing | 400 | Длительность входного видео ещё не измерена, а модель считается посекундно |
file_not_found | 404 | Такого идентификатора файла или генерации нет |
file_not_ready | 409 | Файл ещё обрабатывается |
file_processing_failed | 422 | Обработка файла не удалась |
generation_not_found | 404 | Генерации с таким идентификатором у вас нет |
idempotency_conflict | 409 | Idempotency-Key уже использован с другими параметрами |
idempotency_in_progress | 409 | Запрос с этим Idempotency-Key ещё выполняется |
insufficient_credits | 402 | Кредитов не хватает — на балансе или после вычета занятого другими запусками |
insufficient_scope | 403 | У ключа нет нужного права |
internal_error | 500 | Внутренний сбой сервиса |
invalid_cursor | 400 | Метка страницы не из предыдущего ответа |
invalid_parameters | 400 | Параметры не подходят выбранному варианту |
invalid_request | 400 | Тело или параметр не прошли проверку; перечень проблем в details.issues |
invalid_token | 401 | Ключ отозван или не существует |
not_cancellable | 409 | Генерация запущена в редакторе — такую отменяют там |
payload_too_large | 413 | Тело запроса больше допустимого |
price_unavailable | 400 | Стоимость для таких параметров не складывается |
queue_unavailable | 500 | Очередь генерации недоступна |
rate_limited | 429 | Превышена частота запросов |
service_unavailable | 503 | Сервис временно недоступен |
spend_limit_exceeded | 403 | Задет потолок ключа; какой именно — в details.limitKind |
subscription_required | 403 | Семейство требует действующей подписки |
team_expired | 403 | Срок плана команды истёк |
team_required | 403 | Доступ идёт вместе с командой; чего не хватает — в тексте ошибки |
too_many_concurrent | 429 | Слишком много запросов в работе одновременно |
unauthorized | 401 | Ключа в запросе нет |
unsupported_content_type | 415 | Такой тип содержимого ручка не принимает |
unsupported_file_format | 415 | Содержимое не опознано или такой формат не принимается |
variant_not_resolved | 400 | Ни один вариант не подходит к такому набору входов |
Повторять или нет, говорит retryable в самом ответе: у части кодов это зависит от причины, а не от кода. У всех отказов по частоте и временной недоступности есть заголовок Retry-After.
Отказ самой генерации
Провалившаяся генерация — это ответ 200 с состоянием failed, а не отказ запроса: запрос выполнен, не удалась работа модели. Причина лежит внутри генерации и устроена иначе, чем отказ ручки:
{
"generationId": "8f14e45f-ceea-467a-9a3e-4b1c2d5e7f80",
"state": "failed",
"error": {
"code": "prompt_validation",
"reason": "prompt_too_long",
"message": "The prompt is longer than this model accepts.",
"retryable": false,
"hint": "The model could not work with this prompt. Rewrite it, or pick another family.",
"details": { "limit": 8000 }
}
}
code — класс отказа, список закрыт. hint называет действие, а не диагноз: что менять перед следующей попыткой. details появляется там, где из отказа удалось достать числа — например предел длины промпта у конкретной модели.
| Класс | Что случилось | Что делать |
|---|---|---|
content_policy | Модель отказала по содержанию | Менять промпт или входные файлы: тот же запрос откажет так же |
prompt_validation | Модель не приняла промпт | Переписать промпт или взять другую модель |
parameter_validation | Параметр или вход не подходит модели | Свериться со схемой семейства и поправить запрос |
file_size | Входной файл не укладывается в пределы модели | Взять файл другого размера |
image_size | Размер входной картинки не подходит модели | Взять картинку другого размера |
image_format | Файл не прочитался как изображение | Загрузить заново в поддерживаемом формате |
feature_limitation | Модель не умеет того, о чём просили | Выбрать другое семейство |
model_unavailable | Модель недоступна | Взять другое семейство или повторить позже |
insufficient_credits | Кредиты кончились до старта | Проверить баланс перед повтором |
authentication | Доступ к модели временно закрыт | Повторить позже; запрос ни при чём |
timeout | Модель не ответила вовремя | Повторить: тот же запрос может пройти |
provider_error | Временный сбой модели | Повторить: тот же запрос может пройти |
internal_error | Внутренний сбой сервиса | Повторить: тот же запрос может пройти |
user_cancellation | Генерацию отменили | Ничего — это ответ на отмену |
reason — причина внутри класса, и программировать разное поведение стоит по ней. Один класс покрывает несколько разных отказов: prompt_too_long, prompt_failed и prompt_images_failed — всё это prompt_validation, но первый чинится обрезкой промпта, а последний — заменой входных изображений. Список причин, в отличие от списка классов, открыт и пополняется. Опубликованную причину мы не переименовываем, а незнакомую обрабатывайте по code.
Дословную формулировку модели мы наружу не отдаём — в message приходит наш текст по причине отказа. Чтобы подняли оригинал, назовите generationId в обращении в поддержку.
Причина unclassified при классе internal_error означает, что отказ не удалось отнести ни к одной известной причине. Обрабатывайте его по code; со временем такие отказы получают точную причину.
Частота и одновременность
Ограничений два, и считаются они на пользователя, а не на ключ: сорвавшийся скрипт одного участника команды не должен закрывать API остальным.
Частота. Сейчас это 600 запросов в минуту. Превышение — 429 rate_limited с заголовком Retry-After.
Одновременность. До 32 запросов в работе одновременно. Потолок рассчитан на ожидание через wait, где запрос висит до минуты; больше тридцати двух открытых ожиданий — повод перейти на историю или на вебхуки. Превышение — 429 too_many_concurrent.
Точные числа приходят в заголовках каждого ответа, и опираться стоит на них, а не на значения в тексте:
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 587
X-RateLimit-Reset: 1785974160
X-RateLimit-Reset — момент обнуления счётчика в секундах Unix.
Отдельно от этого действуют потолки траты самого ключа — суточный и разовый. Они описаны в статье Ключ и права.
Потолки размеров
| Что | Предел | При превышении |
|---|---|---|
| Тело запроса | 256 КиБ | 413 payload_too_large |
| Файл | 25 МБ — одинаково для multipart/form-data, ссылки и base64 | Отказ приёма файла |
| Промпт | 20 000 символов | Отказ проверки запроса |
| Медиа-входов в запросе | 20 | Подбор варианта отказывает |
| Страница истории | 50 записей | Значение больше не принимается |
| Ожидание внутри запроса | 60 секунд | Ответ приходит с pollAfterSeconds |
Две последние границы — заслон транспорта, а не пределы моделей: те заметно строже. Сколько входов принимает вариант, видно в подробностях семейства (inputs.images.max и соседние поля), а предел длины промпта — в описании параметра, если модель его объявляет. Лишний файл отвергается подбором варианта с кодом variant_not_resolved, слишком длинный промпт — самой моделью с классом prompt_validation, и там же в details приходит настоящее число.
Машинное описание
GET /api/v1/openapi.json отдаёт спеку OpenAPI: пути, схемы запросов и ответов, коды отказа. Она собирается из тех же схем, которыми проверяется вход, поэтому разойтись с поведением не может.
Спека закрыта тем же ключом, что и остальные ручки, и требует права catalog:read: документ описывает ручки, но не даёт ими пользоваться.