Ошибки Seedance делятся на два уровня: сбой HTTP-запроса (401, 403, 400, 429) и успешный запрос, задача которого в итоге получила статус failed или expired. Считать успехом ответ 200 от интерфейса отправки — самая частая ошибка при подключении видео-API. Правильный порядок диагностики: сначала HTTP-статус, затем статус задачи и поле error, и только потом изменение промпта или модели.

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

Примечание: Seedance, Doubao и Volcano Engine — товарные знаки ByteDance и связанных с ней компаний. Статья носит технический характер и не подразумевает аффилированности или одобрения. Пути и поля в примерах приведены только для демонстрации; перед вызовом сверьтесь с документацией.

1. Сначала различите сбой запроса и сбой задачи

Симптом Уровень Частая причина Действие
401 HTTP Ключ отсутствует, неверный формат, истёк Исправить аутентификацию
403 HTTP Недостаточно прав, модель не активирована, ограничение региона Проверить права и активацию
400 HTTP Параметр вне диапазона, неверное имя модели, недоступный материал Исправить параметры по документации
429 HTTP Ограничение параллелизма, скорости или квоты Задержка, снижение параллелизма
5xx HTTP Перегрузка поставщика или временный сбой Задержка, смена канала
failed Задача Отказ модерации, проблема материала, сбой генерации Прочитать error, исправить материал
expired Задача Не завершена вовремя или результат не забран Пересоздать задачу, проверить срок
Ошибка скачивания Результат Истёк URL, аутентификация, сеть Получить заново или пересохранить

Журнал должен содержать как минимум время, HTTP-статус, код ошибки, имя модели, task_id, номер бизнес-заказа и длительность. Не записывайте полный ключ и не печатайте подписанный URL результата целиком.

2. 401 и 403: сначала заголовок и ключ

401 означает, что идентификация не прошла, и обычно не связан с возможностями модели или балансом. Проверяйте по порядку:

  • Authorization должен быть Bearer <key>; Volcano Ark использует API-ключ как Bearer Token.
  • В ключе не должно быть пробелов, переводов строк или лишних кавычек; переменная окружения должна действительно загружаться.
  • Base URL и ключ должны относиться к одной платформе и одному региону.
  • Ключ не должен быть удалён, ротирован, отключён или не иметь прав проекта.
  • Обратный прокси не должен перезаписывать или отбрасывать заголовок Authorization.

403 чаще означает проблему прав: модель не активирована, у аккаунта нет прав на модель, ограничение региона или соответствия. Для 401 достаточно нового ключа и минимального запроса; для 403 проверяйте статус активации и права в консоли — правка кода обычно не помогает.

3. 429: лимиты, параллелизм и квоты

429 означает превышение скорости, параллелизма или квоты. Типичные ситуации:

  • Несколько сервисов используют один ключ и вытесняют друг друга.
  • Пакетные задачи стартуют одновременно в начале часа, создавая импульс трафика.
  • Повторы идут без задержки, и чем больше сбоев, тем больше запросов — шторм повторов.
  • Длинные задачи занимают весь параллелизм, и короткие не могут попасть в очередь.

Принцип: экспоненциальная задержка со случайным разбросом, снижение параллелизма, разделение ключей по проектам, смещение отправки по времени. Не крутите повторы без задержки; при 429 продолжение частых отправок превращает лимит в затяжной сбой. Если бизнесу действительно нужен высокий параллелизм, заранее подтвердите верхнюю квоту и подготовьте резервный канал.

4. 400: чаще всего ошибки параметров

400 обычно локализуется по тексту ошибки. Проверяйте:

  • Имя и версию модели: копируйте из документации, не собирайте суффикс по памяти.
  • Длительность: диапазоны у моделей разные, например у 2.5 — 4–30 секунд, у 2.0 — 4–15, у 1.0 — 2–12.
  • Разрешение и соотношение сторон: поддерживает ли модель 4K, 21:9 или adaptive.
  • Количество референсных материалов: у 2.5 — до 30 изображений, 10 видео и 10 аудио; у 2.0 лимиты ниже.
  • URL изображения или видео: должен быть доступен платформе, не внутренний адрес и не ссылка с авторизацией.
  • Задачи редактирования или продолжения: часть режимов разрешает только автоматическую длительность, без ручного указания секунд.
  • Аудиовход: часть версий не поддерживает чисто аудиовход.

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

5. Статусы failed и expired

Успешная отправка означает только постановку в очередь. В результате встречаются статусы queued, running, succeeded, failed, expired. Для failed смотрите поле error: отказ модерации, несоответствие входного материала, недоступность референсного изображения, сбой генерации — подходы к ним совершенно разные.

expired обычно означает, что задача не завершилась или результат не забрали до истечения срока. В документации execution_expires_after настраивается, по умолчанию 48 часов; ID задачи хранится 7 дней. После истечения опрос не восстановит задачу — её нужно создавать заново. При использовании callback учитывайте: если подтверждение не пришло за 5 секунд, callback повторяется 3 раза, поэтому интерфейс callback должен быть идемпотентным.

Отказ модерации не стоит обходить перебором формулировок. Сначала подтвердите права на материал, согласие на изображение человека, брендовые элементы и политику контента, затем решайте о повторной отправке.

6. Тайм-ауты и опрос

Тайм-аут делится на три уровня: тайм-аут соединения клиента, тайм-аут одного запроса и общий deadline задачи. Интерфейс отправки обычно быстро возвращает task_id; время уходит на очередь и рендеринг. Слишком короткий тайм-аут HTTP-клиента превратит нормальную отправку в ошибку; слишком длинный — займёт пул потоков.

Опрос рекомендуется начинать с 5 секунд и постепенно увеличивать до 15–30 секунд, задав общий deadline. Если поддерживается callback, используйте его в первую очередь, а опрос — как резерв. Не отправляйте задачу повторно сразу после тайм-аута: сначала проверьте по номеру бизнес-заказа или ключу идемпотентности, нет ли уже запущенной задачи.

7. Сбой скачивания результата

Успех задачи не равен полученному файлу. video_url часто является временным подписанным адресом с ограниченным сроком; если сохранить его в базу и скачать через несколько часов, можно получить 403 или 404. Действия:

  • Сразу после успеха потоково скачать файл в собственное объектное хранилище.
  • При сбое скачивания повторять только скачивание, не пересоздавать задачу генерации.
  • Проверять Content-Type, размер файла и воспроизводимость.
  • Не печатать полный подписанный URL в журнале.

8. Пример: обработка ошибок с задержкой и идемпотентностью

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

import os, time, random, requests

BASE = os.environ["SEEDANCE_BASE_URL"].rstrip("/")
HEADERS = {
    "Authorization": f"Bearer {os.environ['SEEDANCE_API_KEY']}",
    "Content-Type": "application/json",
}

def submit(payload, max_retries=5):
    # перед вызовом проверьте таблицу задач по номеру заказа: если task_id уже есть, используйте его
    for attempt in range(max_retries):
        try:
            r = requests.post(
                f"{BASE}/contents/generations/tasks",
                headers=HEADERS, json=payload, timeout=(5, 30),
            )
        except requests.Timeout:
            time.sleep(min(2 ** attempt, 20) + random.random())
            continue
        if r.status_code == 429 or r.status_code >= 500:
            time.sleep(min(2 ** attempt, 20) + random.random())
            continue
        if r.status_code >= 400:
            raise RuntimeError(f"{r.status_code}: {r.text[:500]}")
        return r.json()["id"]
    raise RuntimeError("submit retries exhausted")

def wait(task_id, deadline_seconds=900):
    deadline = time.time() + deadline_seconds
    delay = 5
    while time.time() < deadline:
        r = requests.get(
            f"{BASE}/contents/generations/tasks/{task_id}",
            headers=HEADERS, timeout=(5, 30),
        )
        if r.status_code == 429 or r.status_code >= 500:
            time.sleep(delay)
            delay = min(delay * 1.5, 30)
            continue
        r.raise_for_status()
        data = r.json()
        if data["status"] == "succeeded":
            return data["content"]["video_url"]
        if data["status"] in ("failed", "expired"):
            raise RuntimeError(f"{data['status']}: {data.get('error')}")
        time.sleep(delay)
        delay = min(delay * 1.5, 30)
    raise TimeoutError(task_id)

def download(url, path):
    with requests.get(url, stream=True, timeout=(5, 120)) as r:
        r.raise_for_status()
        with open(path, "wb") as f:
            for chunk in r.iter_content(1024 * 256):
                f.write(chunk)

Код намеренно не повторяет 400, 401 и 403. Ошибки параметров и аутентификации не исчезнут от повторов — только раздуют журналы и расходы.

9. Повторы, идемпотентность и чек-лист для поддержки

Повторы подходят только для временных ошибок: 429, 5xx, тайм-аут соединения. 400, 401, 403 и отказ модерации автоматически повторять не нужно. Ключ идемпотентности — не число попыток, а номер бизнес-заказа: перед отправкой проверьте таблицу задач, после отправки сохраните task_id, при повторном запросе используйте существующую задачу.

Перед обращением к поставщику соберите информацию по чек-листу:

  1. Время, HTTP-статус, код и полный текст ошибки с обезличиванием.
  2. Имя модели, длительность, разрешение, соотношение сторон и число референсных материалов.
  3. task_id, номер бизнес-заказа, число отправок и число опросов.
  4. Минимальный запрос для воспроизведения без персональных данных и ключей.
  5. Различите сбой запроса и статусы failed или expired.
  6. Проверьте, доступен ли URL материала публично и не слишком ли медленный ответ.
  7. Подтвердите квоты, параллелизм и права аккаунта, исключите 429 и 403.
  8. Приложите ID запроса и время воспроизведения, затем отправляйте на диагностику.

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

Интерфейс отправки вернул 200, почему задача всё равно failed?

200 означает только успешное создание задачи. Генерация видео асинхронная; итоговый статус нужно смотреть в поле status и error результата запроса.

429 означает нехватку баланса?

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

Можно ли сразу повторить задачу после failed?

Сначала прочитайте error. При отказе модерации и несоответствии материала повтор в том же виде обычно снова не пройдёт; при сетевом или серверном сбое можно повторить с задержкой. Перед повтором проверьте идемпотентность по номеру бизнес-заказа.

Как часто опрашивать задачу?

Начинайте с 5 секунд, постепенно увеличивайте до 15–30 секунд и задайте общий тайм-аут. Если есть callback, используйте его в первую очередь, опрос — как резерв.

Что делать, если URL результата не открывается?

Чаще всего истёк срок или подпись. После успеха сразу пересохраняйте файл в объектное хранилище; если срок уже истёк, заново запросите задачу или создайте её, не повторяйте запросы к старой ссылке.

Что дальше

Создайте тестовый ключ в ZSQH AI Gateway, отработайте по одному разу 401, 429, ошибку параметров и сбой задачи, убедитесь, что оповещения и стратегия повторов работают. Доступность моделей и тарификация — на странице цены на модели.

Связанные статьи: