Cómo funciona

Códigos de error de la API de vídeo con IA: qué significan y cuándo reintentar

Los trabajos de generación de vídeo fallan más a menudo que las llamadas a una API normal: los modelos se saturan, rechazan prompts o agotan el tiempo de espera. Esta guía enumera todos los errores que puedes recibir, cuáles vale la pena reintentar y cómo hacerlo de forma segura.

Dos lugares donde puede aparecer un error

Un trabajo de vídeo o imagen puede fallar en dos momentos, y tu código tiene que gestionar ambos:

  1. Al enviarlo. POST /v1/generations responde con un estado de error HTTP y un cuerpo como {"error": {"code": "...", "message": "..."}}. No se inició nada y no se cobra nada.
  2. Mientras se ejecuta. El envío funcionó y devolvió 202, pero el trabajo termina después con status: "failed". Su error incluye un code, un message que puedes mostrar a quien lo pidió, y retryable.

Un trabajo fallido nunca se cobra, con ningún modelo. El precio se retiene de tu saldo al enviar y se libera si el trabajo falla.

Errores HTTP al enviar

Códigos de error HTTP del endpoint de generaciones
EstadoCódigoSignificado¿Reintentar?
400invalid_requestEl cuerpo no es JSON, le falta model o input, o contiene un campo que la API no conoce.No. Corrige el cuerpo.
401unauthorizedFalta la clave de API o es incorrecta.No. Revisa la clave.
402insufficient_creditsEl saldo no cubre el precio retenido para el trabajo.Después de recargar.
403account_disabled, generation_not_enabledLa cuenta está en pausa, o la clave puede consultar precios pero no generar.No. Contacta con soporte.
404not_foundNo hay ninguna generación con ese id en tu cuenta.No.
409idempotency_conflictLa Idempotency-Key ya se usó con un cuerpo distinto.Con una clave nueva.
409not_readyPediste el archivo antes de que el trabajo terminara con éxito.Sí, una vez que haya terminado con éxito.
413body_too_largeEl cuerpo JSON supera 1 MB. Sube los archivos y envía enlaces.No. Reduce el cuerpo.
422invalid_inputUn valor que el modelo no admite, como una duración o un tamaño que no figura en su lista. El mensaje indica cuál.No. Cambia el valor.
422max_cost_exceededTodas las rutas cuestan más que tu max_cost_usd.No. Sube el límite o reduce los ajustes.
422model_not_availableNo existe ningún modelo con ese id.No. Revisa el id.
429rate_limitedDemasiadas solicitudes en el mismo segundo desde una cuenta.Sí, después de Retry-After.
429concurrency_limitLa cuenta ya tiene el máximo de trabajos en ejecución.Sí, cuando termine alguno.
500server_errorAlgo falló por nuestra parte.Sí, con la misma Idempotency-Key.
503busyUn momento de carga alta.Sí, después de Retry-After, con la misma clave.
503model_unavailableAhora mismo no hay ninguna ruta disponible para este modelo.Sí, en breve.

La regla general: vale la pena reintentar 429, 500 y 503 con espera progresiva; cualquier error del rango 4xx salvo 429 significa que hay que cambiar la solicitud en sí.

Por qué falla un trabajo después de empezar

Códigos de error de una generación fallida
error.coderetryableQué pasó
content_policynoEl modelo rechazó el prompt o los archivos, o retuvo su resultado. reason indica el motivo: sexual, minors, copyright, real_person o other.
invalid_inputnoNo se pudo leer una referencia, o el modelo rechazó un valor. El mensaje indica cuál.
model_declinednoEl modelo respondió con texto en lugar de crear la imagen o el vídeo. Describe el resultado en sí en el prompt.
reference_changednoUn archivo de referencia cambió después de verificarse. Envíalo de nuevo.
max_cost_exceedednoLa única ruta que puede ejecutarlo cuesta más que tu límite.
model_busyyesTodas las rutas estaban al límite de capacidad. Inténtalo de nuevo en un minuto.
model_unavailableyesNinguna ruta pudo aceptar el trabajo en este momento.
timeoutyesNinguna ruta devolvió un resultado a tiempo, o se superó tu max_wait_s.
all_routes_failedyesTodas las rutas fallaron por motivos de su lado.

Entre bambalinas, cuando un trabajo llega a una ruta saturada o averiada, pasa por sí solo a la siguiente, así que cuando ves model_busy o all_routes_failed ya se probaron todas las rutas. El campo attempts indica cuántas. Esperar uno o dos minutos antes de volver a intentarlo suele bastar.

Rechazos por contenido

content_policy es el fallo más frecuente. Lo decide el modelo, no la API, y el reason indica qué regla se activó. Las causas habituales son el nombre o el rostro de una persona famosa en el prompt o en una imagen de referencia (real_person), marcas y personajes conocidos (copyright) y cualquier cosa que parezca implicar a un menor. Reintentar la misma solicitud no sirve: reformula el prompt o cambia la imagen. Los modelos difieren en su nivel de rigor, así que el mismo prompt puede pasar en uno y ser rechazado en otro.

Un bucle de reintentos que hace lo correcto

Este helper de Python reintenta lo que vale la pena y se detiene ante lo que no. Importan dos detalles:

  • Reenviar un envío tras un 503 o una conexión caída usa la misma Idempotency-Key, así que nunca puede iniciar un segundo trabajo de pago.
  • Volver a intentarlo cuando un trabajo falló usa una clave nueva. La misma clave solo devolvería el trabajo fallido.
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"])

El trabajo de ejemplo es un clip de Seedance 2.0 Fast de 5 segundos en 480p, que cuesta $0.25 si termina bien y nada si falla. El límite max_cost_usd evita que un ajuste equivocado cueste más de lo esperado.

Cómo evitar errores desde el principio

  • Lee las opciones antes de enviar. GET /v1/models y la página de modelos enumeran los tamaños, las duraciones y los límites de referencias de cada modelo. Un valor fuera de ellos se rechaza al instante con 422 invalid_input.
  • Sube los archivos en lugar de incrustarlos. POST /v1/uploads acepta imágenes de hasta 30 MB, clips de hasta 50 MB y audio de hasta 15 MB, y devuelve un enlace válido durante 14 días, lo que mantiene pequeño el cuerpo de la solicitud.
  • Comprueba tu saldo desde el código. GET /v1/balance antes de un lote grande te ahorra una racha de errores 402. Los paquetes de créditos están en la página de precios.

Para reducir lo que cuestan los trabajos que sí terminan, consulta cómo reducir los costes de la API de vídeo con IA. La referencia completa de errores está en la documentación; obtén una clave de API para probarlo.

Preguntas frecuentes

¿Se me cobra si falla una generación de vídeo con IA?

No. El precio se retiene al enviar el trabajo y se libera si este falla, sea cual sea el motivo.

¿Qué errores debo reintentar?

Al enviar, reintenta 429, 500 y 503 después del tiempo indicado en Retry-After. En un trabajo fallido, reintenta cuando error.retryable sea true: model_busy, model_unavailable, timeout y all_routes_failed.

¿Qué significa content_policy?

El modelo rechazó el prompt o los archivos, o retuvo lo que generó. El campo reason indica la regla: sexual, minors, copyright, real_person u other. Cambia la solicitud en lugar de reintentarla.

¿Cómo reintento sin pagar dos veces?

Envía un encabezado Idempotency-Key y reutilízalo cuando vuelvas a enviar tras un timeout o un 503. Recibirás la misma generación, no una segunda.

¿Qué significa 422 invalid_input?

El modelo no admite un valor que enviaste, como una duración, un tamaño o un número de imágenes de referencia. El mensaje indica el campo y lo que admite.

Crea sobre una API que nunca cobra un fallo

Una clave de API para todos los modelos de vídeo e imagen, con respaldo automático entre rutas. Crédito prepago desde $10, cobrado solo por los trabajos que terminan con éxito.