Skip to main content
Ошибки возникают в двух разных местах и описываются двумя разными наборами понятий:
  • Ошибки запросов к API — HTTP-ответ на синхронный вызов API (аутентификация, оплата, некорректный запрос, отсутствующий ресурс). См. Ошибки запросов к API.
  • Коды сбоев prediction — запрос принят и поставлен в очередь, но сам prediction завершился со status: "failed". Сбой описывается объектом error внутри prediction, который вы получаете от эндпоинтов статуса prediction, в доставках webhook и от эндпоинта результата. См. Коды сбоев prediction.

Коды сбоев prediction

Prediction, завершившийся сбоем, содержит объект error:
Сбойные prediction не тарифицируются; кредиты, зарезервированные под этот запрос, освобождаются. Prediction, который не завершился сбоем, содержит error: null. См. Примечание о миграции, если вы делали интеграцию до 17 августа 2026 года.

Где вы получаете ошибку

Один и тот же объект error публикуется во всех каналах, поэтому читать его можно там, куда вы и так смотрите:

Чтение сбоя из эндпоинта результата

Запрос вывода у prediction, завершившегося сбоем, возвращает 400 с тем самым сбоем, который к этому привёл, под кодом уровня запроса PREDICTION_FAILED:
Два кода на двух уровнях, и это разные наборы понятий:
  • error.code равен PREDICTION_FAILED — это ошибка запроса к API, означающая «prediction, вывод которого вы запросили, его не произвёл»;
  • error.details — это собственный объект error этого prediction, идентичный тому, что по тому же запросу сообщает /status, поэтому два эндпоинта никогда не могут разойтись в причине сбоя. Ветвитесь по error.details.reason и error.details.retryable.
error.message повторяет сообщение prediction, так что даже клиент, читающий только сообщение верхнего уровня, получает что-то полезное. Два timestamp, два смысла. timestamp верхнего уровня — это момент формирования данного HTTP-ответа; error.details.timestamp — момент сбоя prediction. Для prediction, который вы запрашиваете спустя дни, они разойдутся на дни. Когда речь о сбое, читайте внутренний. Официальные клиентские библиотеки распаковывают это за вас: result() выбрасывает ошибку, у которой code, reason и retryable — собственные значения prediction, те же, что subscribe() выбрасывает для того же сбоя. Prediction, который всё ещё в очереди или выполняется, а также отменённый, по-прежнему возвращает тот же общий 400, что и раньше.

Как решить, повторять ли запрос

Смотрите на retryable. Это поле отвечает ровно на один вопрос — даст ли повторная отправка точно такого же запроса другой результат? — и не зависит от code: один и тот же code в одном сбое может допускать повтор, а в другом — нет. retryable необязательное. Когда оно отсутствует, используйте значение по умолчанию для соответствующего code из таблицы ниже. Именно так Sunra вёл себя до появления этого поля, поэтому откат к умолчанию всегда безопасен — он просто менее точен.

code

reason

reason называет конкретную причину, стоящую за code. Используйте его для метрик, маршрутизации и диагностики в поддержке; решение о повторе принимайте по retryable. У каждого опубликованного сегодня reason ниже есть собственный раздел, и его якорь — сам reason: #input_fetch_failed, #moderation_blocked и так далее, — поэтому из отчёта об ошибке можно сослаться сразу на значение.

input_validation_failed

code: invalid_input · retryable: false Запрос не прошёл собственную валидацию схемы или параметров в Sunra. message называет проблемное поле. Что делать: исправьте названное поле. Тот же запрос будет падать и дальше.

provider_rejected_input

code: invalid_input · retryable: false Провайдер модели отклонил один или несколько входных параметров. Если провайдер сообщает, какие именно, это отражается в message; некоторые провайдеры сообщают лишь о том, что входные данные неприемлемы, — и тогда мы так и пишем, вместо того чтобы гадать. Что делать: сверьте свои параметры со схемой модели — значение вне диапазона, неподдерживаемое сочетание, соотношение сторон или длительность, которые модель не принимает.

input_fetch_failed

code: invalid_input · retryable: false или true Не удалось загрузить входной файл, указанный по URL. Это единственный reason, у которого retryable действительно меняется, поэтому читайте поле, а не додумывайте:
  • false — хост нам отказал: 4xx, адрес, с которого нам не разрешено загружать, редирект или файл сверх лимита размера;
  • true — хост был кратковременно недоступен: 5xx, таймаут или ошибка DNS.
В message возвращается отправленный вами URL, чтобы вы поняли, какой именно вход не загрузился, — но без query string, поэтому учётные данные из presigned URL никогда не отражаются обратно к вам:
Что делать: когда retryable равен false, проверьте, доступен ли URL публично и не истёк ли срок presigned-ссылки. Когда true — повторите запрос.

moderation_blocked

code: unsafe_content · retryable: false Заблокировано системой контентной безопасности провайдера модели — это может быть как входящий промпт и медиа, так и сгенерированный результат. Что делать: измените промпт или медиафайл. Повторная отправка того же содержимого снова будет заблокирована.

provider_rate_limited

code: service_provider_error · retryable: true Провайдер модели ограничивает частоту запросов. Что делать: повторите с экспоненциальной задержкой или направьте запрос на другую модель.

provider_unavailable

code: service_provider_error · retryable: true Провайдер модели не смог обслужить запрос. Что делать: повторите позже или направьте запрос на другую модель.

provider_timeout

code: task_timeout · retryable: true Prediction не завершился за отведённое время. Что делать: повторите — период меньшей нагрузки или запрос поменьше (короче длительность, ниже разрешение) повышают шансы.

provider_account_error

code: internal_server_error · retryable: false Проблема с нашей собственной учётной записью у провайдера модели — оплата, учётные данные или постоянная квота. Это наша вина, а не проблема ваших входных данных. Что делать: с вашей стороны ничего; повтор не поможет, а оповещение мы получаем автоматически. Направьте запрос на другую модель, если мощности нужны прямо сейчас.

endpoint_misconfigured

code: internal_server_error · retryable: false Этот эндпоинт модели неверно настроен на нашей стороне. Что делать: с вашей стороны ничего; повтор не поможет, а оповещение мы получаем автоматически. Если вопрос срочный, обратитесь в поддержку и укажите request_id.

queue_enqueue_failed

code: internal_server_error · retryable: true Не удалось поставить prediction в очередь. Что делать: отправьте запрос повторно.

reaped_stalled

code: internal_server_error · retryable: true Prediction завис и был принудительно завершён. Что делать: отправьте запрос повторно.

Неизвестные значения

И code, и reason являются открытыми множествами. По мере того как мы классифицируем всё больше сбоев, новые значения добавляются без объявления breaking change. Ваша интеграция не должна падать, терять ошибку или отвергать payload, встретив незнакомое значение.
  • Неизвестный reason — считайте, что reason отсутствует, и принимайте решение по retryable (или по умолчанию для code). Сохраните исходное значение в логах: это самый быстрый способ для поддержки опознать сбой.
  • Неизвестный code — считайте его internal_server_error. Одно служебное значение стоит знать по имени: unknown_error_code — его Sunra отдаёт, когда prediction завершился сбоем, но восстановить для него какую-либо классификацию не удалось.

Примечание о миграции: error равен null, когда ошибки нет

Действует с 17 августа 2026 года. У объекта error одно и то же представление во всех каналах. Три различия между ними исчезли:
  • error равен null, если prediction не завершился сбоем. GET /v1/predictions/{prediction_id} раньше отвечал пустым объектом — "error": {} — для каждого успешного, стоящего в очереди или отменённого prediction. Теперь он отвечает "error": null, как это уже делает эндпоинт статуса очереди. Если вы проверяете объект на пустоту (Object.keys(response.error).length === 0), замените эту проверку на проверку на null (response.error === null).
  • Сбой всегда несёт непустые code и message. Там, где для сбоя было записано нечто, что мы не можем классифицировать, вы теперь получаете служебное значение unknown_error_code и общее сообщение — вместо поля, которое отсутствует, пусто или не является строкой.
  • Сбои, записанные простым текстом, доходят до вас текстом. Небольшое число prediction за апрель 2026 года сохранило свою ошибку в виде обычной строки. GET /v1/predictions/{prediction_id} раньше её отбрасывал, а эндпоинт статуса очереди подменял её служебным сообщением; теперь оба публикуют её как message под code: "unknown_error_code".
Ничего не удалено и новых полей не появилось: error и раньше присутствовал в каждом из этих ответов — изменилось только его значение. Доставки webhook не затронуты: именно к их форме сошлись остальные каналы, — и error по-прежнему отсутствует в доставке succeeded, а не отправляется как null. Окно совместимости. Периода двойной выдачи нет: с этой даты API перестал отдавать "error": {}. Если вы воспроизводите или повторно обрабатываете payload, собранные до неё, считайте null и {} одним и тем же — пока эти сохранённые данные не выйдут из обращения.

Предстоящее изменение: часть сбоев получит более точный code

Сегодня значительная доля сбоев сообщается как service_provider_error, включая многие, которые не являются ни временными, ни виной провайдера. По мере того как мы классифицируем провайдеров одного за другим, такие сбои переходят к тому code, который действительно их описывает:
  • детерминированный отказ провайдера принять ваши входные данные становится invalid_input (ранее service_provider_error);
  • проблема на стороне Sunra, например неверно настроенный эндпоинт или наша учётная запись у провайдера, становится internal_server_error (ранее service_provider_error);
  • входной файл, который не удалось загрузить, становится invalid_input (ранее internal_server_error).
Ни один код не переименовывается и не удаляется, новых значений code не вводится — пять значений выше остаются полным набором классифицированных кодов. Меняется лишь то, какой из них получает конкретный сбой, и меняется постепенно, провайдер за провайдером. Если ваш код ветвится по code, сейчас удачный момент перевести эту логику на retryable и reason: они описывают сбой напрямую и не затрагиваются переклассификацией.

Ошибки запросов к API