Como funciona

Códigos de erro da API de vídeo com IA: o que significam e quando tentar de novo

Jobs de geração de vídeo falham mais do que chamadas de API comuns: os modelos ficam ocupados, recusam prompts ou estouram o tempo limite. Este guia lista todos os erros que você pode receber, quais vale a pena tentar de novo e como fazer isso com segurança.

Dois momentos em que um erro pode aparecer

Um job de vídeo ou imagem pode dar errado em dois momentos, e seu código precisa tratar os dois:

  1. Ao enviar. POST /v1/generations responde com um status HTTP de erro e um corpo como {"error": {"code": "...", "message": "..."}}. Nada foi iniciado e nada é cobrado.
  2. Durante a execução. O envio funcionou com 202, mas o job termina depois com status: "failed". O error traz um code, uma message que você pode mostrar a quem fez o pedido e retryable.

Um job que falha nunca é cobrado, em nenhum modelo. O valor é reservado do seu saldo no envio e liberado se o job falhar.

Erros HTTP no envio

Códigos de erro HTTP do endpoint de generations
StatusCódigoSignificadoTentar de novo?
400invalid_requestO corpo não é JSON, não tem model ou input, ou contém um campo que a API não conhece.Não. Corrija o corpo.
401unauthorizedA chave de API está ausente ou incorreta.Não. Verifique a chave.
402insufficient_creditsO saldo não cobre o valor reservado para o job.Depois de recarregar.
403account_disabled, generation_not_enabledA conta está pausada, ou a chave consegue consultar preços, mas não gerar.Não. Fale com o suporte.
404not_foundNão existe geração com esse id na sua conta.Não.
409idempotency_conflictO Idempotency-Key já foi usado com um corpo diferente.Com uma nova chave.
409not_readyVocê pediu o arquivo antes de o job ser concluído com sucesso.Sim, depois que ele for concluído com sucesso.
413body_too_largeO corpo JSON tem mais de 1 MB. Faça upload dos arquivos e envie links.Não. Reduza o corpo.
422invalid_inputUm valor que o modelo não aceita, como uma duração ou um tamanho que ele não lista. A mensagem indica qual.Não. Altere o valor.
422max_cost_exceededTodas as rotas custam mais do que o seu max_cost_usd.Não. Aumente o limite ou reduza as configurações.
422model_not_availableNão existe modelo com esse id.Não. Verifique o id.
429rate_limitedMuitas requisições no mesmo segundo vindas de uma conta.Sim, depois de Retry-After.
429concurrency_limitA conta já tem o número máximo de jobs em execução.Sim, quando um terminar.
500server_errorAlgo falhou do nosso lado.Sim, com o mesmo Idempotency-Key.
503busyUm momento de carga alta.Sim, depois de Retry-After, com a mesma chave.
503model_unavailableNenhuma rota deste modelo está disponível agora.Sim, em instantes.

A regra geral: 429, 500 e 503 valem uma nova tentativa com backoff; qualquer erro da faixa 4xx, exceto 429, significa que a própria requisição precisa mudar.

Por que um job falha depois de iniciado

Códigos de erro de uma geração que falhou
error.coderetryableO que aconteceu
content_policynoO modelo recusou o prompt ou a mídia, ou reteve o resultado. reason informa o motivo: sexual, minors, copyright, real_person ou other.
invalid_inputnoNão foi possível ler uma referência, ou o modelo rejeitou um valor. A mensagem indica qual.
model_declinednoO modelo respondeu com palavras em vez de criar a imagem ou o vídeo. Descreva o próprio resultado no prompt.
reference_changednoUm arquivo de referência mudou depois de ser verificado. Envie-o de novo.
max_cost_exceedednoA única rota capaz de executar custa mais do que o seu limite.
model_busyyesTodas as rotas estavam no limite de capacidade. Tente de novo em um minuto.
model_unavailableyesNenhuma rota pôde assumir o job agora.
timeoutyesNenhuma rota devolveu um resultado a tempo, ou o seu max_wait_s passou.
all_routes_failedyesTodas as rotas falharam por motivos do lado delas.

Nos bastidores, um job que cai em uma rota ocupada ou com defeito passa sozinho para a próxima rota. Portanto, quando você vê model_busy ou all_routes_failed, todas as rotas já foram tentadas. O campo attempts informa quantas. Esperar um ou dois minutos antes de tentar de novo costuma bastar.

Recusas de conteúdo

content_policy é a falha mais comum. Quem decide é o modelo, não a API, e o reason indica qual regra foi acionada. As causas mais frequentes são o nome ou o rosto de uma pessoa famosa no prompt ou em uma imagem de referência (real_person), marcas e personagens conhecidos (copyright) e qualquer coisa que pareça envolver um menor. Tentar a mesma requisição de novo não ajuda; reescreva o prompt ou troque a imagem. Os modelos variam em rigor, então o mesmo prompt pode passar em um e ser recusado em outro.

Um loop de retry que faz a coisa certa

Este helper em Python tenta de novo o que vale a pena e para no que não vale. Dois detalhes importam:

  • Reenviar uma submissão após um 503 ou uma conexão interrompida usa o mesmo Idempotency-Key, então nunca inicia um segundo job cobrado.
  • Tentar de novo depois que um job falhou usa uma chave nova. A mesma chave só devolveria o job que falhou.
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"])

O job de exemplo é um clipe de 5 segundos em 480p com Seedance 2.0 Fast, que custa $0.25 se der certo e nada se falhar. O limite max_cost_usd impede que uma configuração errada custe mais do que o esperado.

Como evitar erros desde o início

  • Leia as opções antes de enviar. GET /v1/models e a página de modelos listam os tamanhos, as durações e os limites de referência de cada modelo. Um valor fora deles é recusado na hora com 422 invalid_input.
  • Faça upload dos arquivos em vez de embuti-los. POST /v1/uploads aceita imagens de até 30 MB, clipes de até 50 MB e áudio de até 15 MB e devolve um link válido por 14 dias, o que mantém o corpo da requisição pequeno.
  • Verifique seu saldo no código. GET /v1/balance antes de um lote grande evita uma sequência de erros 402. Os pacotes de créditos estão na página de preços.

Para formas de reduzir o custo dos jobs bem-sucedidos, veja como reduzir o custo da API de vídeo com IA. A referência completa de erros está na documentação; obtenha uma chave de API para testar.

Perguntas frequentes

Sou cobrado quando uma geração de vídeo com IA falha?

Não. O valor fica reservado quando você envia e é liberado se o job falhar, seja qual for o motivo.

Quais erros devo tentar de novo?

No envio, tente de novo 429, 500 e 503 depois do atraso indicado em Retry-After. Em um job que falhou, tente de novo quando error.retryable for true: model_busy, model_unavailable, timeout e all_routes_failed.

O que significa content_policy?

O modelo recusou o prompt ou a mídia, ou reteve o que gerou. O campo reason indica a regra: sexual, minors, copyright, real_person ou other. Altere a requisição em vez de tentar de novo.

Como tentar de novo sem pagar duas vezes?

Envie o header Idempotency-Key e reutilize-o ao reenviar após um timeout ou um 503. Você recebe a mesma geração de volta, não uma segunda.

O que significa 422 invalid_input?

O modelo não aceita um valor que você enviou, como duração, tamanho ou número de imagens de referência. A mensagem indica o campo e o que ele aceita.

Crie sobre uma API que nunca cobra uma falha

Uma chave de API para todos os modelos de vídeo e imagem, com fallback automático entre rotas. Crédito pré-pago a partir de $10, cobrado apenas pelos jobs que dão certo.