Как это работает

Коды ошибок API для AI-видео: что они значат и когда повторять запрос

Задачи генерации видео завершаются ошибкой чаще, чем обычные вызовы API: модели бывают заняты, отклоняют промпты или не укладываются в тайм-аут. В этом руководстве перечислены все ошибки, которые вы можете получить, какие из них стоит повторять и как делать это безопасно.

Два места, где может возникнуть ошибка

Задача генерации видео или изображения может завершиться неудачей в два момента, и ваш код должен обрабатывать оба:

  1. При отправке. POST /v1/generations отвечает HTTP-статусом ошибки и телом вида {"error": {"code": "...", "message": "..."}}. Ничего не запущено, ничего не списано.
  2. Во время выполнения. Отправка прошла успешно и вернула 202, но позже задача завершается со статусом status: "failed". В её error есть code, message, который можно показать пользователю, сделавшему запрос, и retryable.

Неудавшаяся задача не тарифицируется ни на одной модели. Стоимость резервируется на вашем балансе при отправке и освобождается, если задача завершилась ошибкой.

HTTP-ошибки при отправке

Коды HTTP-ошибок эндпоинта генераций
СтатусКодЗначениеПовторять?
400invalid_requestТело запроса не в формате JSON, в нём нет model или input, либо есть поле, которое API не знает.Нет. Исправьте тело запроса.
401unauthorizedAPI-ключ отсутствует или неверен.Нет. Проверьте ключ.
402insufficient_creditsБаланса не хватает на стоимость, зарезервированную для задачи.После пополнения.
403account_disabled, generation_not_enabledАккаунт приостановлен, или ключ позволяет смотреть цены, но не запускать генерацию.Нет. Напишите в поддержку.
404not_foundНа вашем аккаунте нет генерации с таким id.Нет.
409idempotency_conflictIdempotency-Key уже использовался с другим телом запроса.С новым ключом.
409not_readyВы запросили файл до того, как задача успешно завершилась.Да, после успешного завершения.
413body_too_largeJSON-тело запроса больше 1 МБ. Загружайте файлы и отправляйте ссылки.Нет. Уменьшите тело запроса.
422invalid_inputЗначение, которое модель не принимает, например длительность или размер, которых нет в её списке. В сообщении указано, какое именно.Нет. Измените значение.
422max_cost_exceededЛюбой маршрут стоит больше, чем ваш max_cost_usd.Нет. Увеличьте лимит или снизьте настройки.
422model_not_availableМодели с таким id нет.Нет. Проверьте id.
429rate_limitedСлишком много запросов за одну секунду с одного аккаунта.Да, через Retry-After.
429concurrency_limitНа аккаунте уже запущено максимальное число задач.Да, когда одна из них завершится.
500server_errorЧто-то сломалось на нашей стороне.Да, с тем же Idempotency-Key.
503busyКратковременная нагрузка.Да, через Retry-After, с тем же ключом.
503model_unavailableСейчас нет доступного маршрута для этой модели.Да, чуть позже.

Практическое правило: 429, 500 и 503 стоит повторять с нарастающей задержкой; всё из диапазона 4xx, кроме 429, означает, что нужно изменить сам запрос.

Почему задача завершается ошибкой после запуска

Коды ошибок неудавшейся генерации
error.coderetryableЧто произошло
content_policynoМодель отклонила промпт или медиафайл либо не отдала результат. reason объясняет причину: sexual, minors, copyright, real_person или other.
invalid_inputnoРеференс не удалось прочитать, или модель отклонила значение. В сообщении указано, какое именно.
model_declinednoМодель ответила словами вместо того, чтобы создать изображение или видео. Опишите в промпте сам результат.
reference_changednoФайл-референс изменился после проверки. Отправьте его снова.
max_cost_exceedednoЕдинственный доступный для запуска маршрут стоит больше вашего лимита.
model_busyyesВсе маршруты были перегружены. Повторите через минуту.
model_unavailableyesСейчас ни один маршрут не может принять задачу.
timeoutyesНи один маршрут не вернул результат вовремя, либо истёк ваш max_wait_s.
all_routes_failedyesНа каждом маршруте произошёл сбой с его стороны.

Если задача попадает на занятый или неисправный маршрут, она сама переходит на следующий, так что к моменту, когда вы видите model_busy или all_routes_failed, все маршруты уже опробованы. Поле attempts показывает, сколько их было. Обычно достаточно подождать минуту-две и повторить.

Отказы по содержанию

content_policy — самая частая ошибка. Решает её модель, а не API, и reason показывает, какое правило сработало. Типичные причины: имя или лицо известного человека в промпте или референсе (real_person), бренды и известные персонажи (copyright), а также всё, что выглядит как изображение несовершеннолетнего. Повтор того же запроса не поможет; переформулируйте промпт или замените изображение. Модели различаются по строгости, поэтому один и тот же промпт может пройти на одной и быть отклонён на другой.

Цикл повторов, который делает всё правильно

Эта функция на Python повторяет то, что стоит повторять, и останавливается на том, что не стоит. Важны две детали:

  • Повторная отправка после 503 или обрыва соединения использует тот же Idempotency-Key, поэтому она никогда не запустит вторую платную задачу.
  • Повтор после того, как задача завершилась ошибкой, использует новый ключ. Тот же ключ просто вернул бы неудавшуюся задачу.
Python
import os
import time
import uuid

import requests

API = "https://api.revana.si/v1"
AUTH = {"Authorization": f"Bearer {os.environ['REVANA_API_KEY']}"}
RETRY_HTTP = {429, 500, 503}


class GenerationError(Exception):
    pass


def submit(body):
    """POST a job. Retries 429, 500 and 503 with the same Idempotency-Key, so a retry never starts a second job."""
    headers = {**AUTH, "Idempotency-Key": str(uuid.uuid4())}
    for attempt in range(6):
        r = requests.post(f"{API}/generations", headers=headers, json=body, timeout=60)
        if r.ok:
            return r.json()
        if r.status_code in RETRY_HTTP:
            time.sleep(float(r.headers.get("Retry-After", 2 ** attempt)))
            continue
        err = r.json()["error"]  # 400, 401, 402, 403, 409, 413, 422: fix the request, do not retry
        raise GenerationError(f"{r.status_code} {err['code']}: {err['message']}")
    raise GenerationError("still busy after 6 tries")


def wait(job):
    while job["status"] in ("queued", "running"):
        time.sleep(5)
        job = requests.get(f"{API}/generations/{job['id']}", headers=AUTH).json()
    return job


def generate(body, tries=3):
    for n in range(tries):
        job = wait(submit(body))  # each call uses a new key: a failed job is final
        if job["status"] == "succeeded":
            return job
        err = job["error"]
        if not err["retryable"]:
            raise GenerationError(f"{err['code']}: {err['message']}")
        time.sleep(60 * (n + 1))  # model_busy, timeout and the like: wait, then try again
    raise GenerationError(f"gave up after {tries} tries: {err['code']}")


job = generate({
    "model": "seedance-2.0-fast",
    "input": {"prompt": "Waves roll onto black sand at sunset.", "resolution": "480p", "duration": 5},
    "max_cost_usd": 0.3,
})
print(job["output"]["urls"][0], job["cost_usd"])

Пример задачи — 5-секундный клип Seedance 2.0 Fast в 480p, который стоит $0.25 при успехе и ничего при ошибке. Лимит max_cost_usd не даст неверной настройке обойтись дороже ожидаемого.

Как избежать ошибок заранее

  • Прочитайте параметры до отправки. GET /v1/models и страница моделей перечисляют размеры, длительности и лимиты референсов каждой модели. Значение за их пределами сразу отклоняется с ошибкой 422 invalid_input.
  • Загружайте файлы, а не встраивайте их. POST /v1/uploads принимает изображения до 30 МБ, видео до 50 МБ и звук до 15 МБ и возвращает ссылку, действующую 14 дней, так что тело запроса остаётся небольшим.
  • Проверяйте баланс в коде. GET /v1/balance перед большой партией избавит от серии ошибок 402. Пакеты кредитов — на странице цен.

О том, как снизить стоимость успешных задач, читайте в статье как сократить расходы на API для AI-видео. Полный справочник ошибок — в документации; получите API-ключ, чтобы попробовать.

Частые вопросы

Спишутся ли деньги, если генерация видео завершилась ошибкой?

Нет. Стоимость резервируется при отправке задачи и освобождается, если задача завершилась ошибкой, независимо от причины.

Какие ошибки стоит повторять?

При отправке повторяйте 429, 500 и 503 после задержки из Retry-After. Если задача завершилась ошибкой, повторяйте, когда error.retryable равно true: model_busy, model_unavailable, timeout и all_routes_failed.

Что означает content_policy?

Модель отклонила промпт или медиафайл либо не отдала то, что создала. Поле reason указывает правило: sexual, minors, copyright, real_person или other. Измените запрос, а не повторяйте его.

Как повторить запрос, не заплатив дважды?

Отправьте заголовок Idempotency-Key и используйте тот же ключ при повторной отправке после таймаута или ответа 503. Вы получите ту же генерацию, а не вторую.

Что означает 422 invalid_input?

Модель не принимает отправленное вами значение, например длительность, размер или число референсных изображений. В сообщении указано поле и допустимые значения.

Стройте на API, который никогда не списывает деньги за неудачу

Один API-ключ для всех моделей видео и изображений с автоматическим переходом между маршрутами. Предоплаченные кредиты от $10, списание только за успешные задачи.