작동 방식

AI 영상 API 오류 코드: 의미와 재시도 시점

영상 생성 작업은 일반 API 호출보다 실패하는 경우가 많습니다. 모델이 바쁘거나, 프롬프트를 거부하거나, 시간이 초과되기 때문입니다. 이 가이드는 받을 수 있는 모든 오류와 재시도할 가치가 있는 오류, 안전하게 재시도하는 방법을 정리합니다.

오류가 나타나는 두 지점

영상 또는 이미지 작업은 두 시점에서 문제가 생길 수 있으며, 코드에서 둘 다 처리해야 합니다.

  1. 제출할 때. POST /v1/generations가 HTTP 오류 상태와 {"error": {"code": "...", "message": "..."}} 같은 본문으로 응답합니다. 아무것도 시작되지 않았고 요금도 청구되지 않습니다.
  2. 실행 중에. 제출은 202로 성공했지만, 작업이 나중에 status: "failed"로 끝납니다. error에는 code, 요청한 사람에게 보여 줄 수 있는 message, 그리고 retryable가 들어 있습니다.

실패한 작업은 어떤 모델에서도 요금이 청구되지 않습니다. 제출할 때 잔액에서 금액이 보류되고, 작업이 실패하면 보류가 해제됩니다.

제출 시 HTTP 오류

generations 엔드포인트의 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 MB를 넘습니다. 파일을 업로드하고 링크를 보내세요.아니요. 본문 크기를 줄이세요.
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은 백오프를 두고 재시도할 가치가 있습니다. 429를 제외한 4xx 범위의 오류는 요청 자체를 바꿔야 한다는 뜻입니다.

작업이 시작된 후 실패하는 이유

실패한 생성의 오류 코드
error.coderetryable발생한 일
content_policyno모델이 프롬프트나 미디어를 거부했거나 결과물을 제공하지 않았습니다. reason가 이유를 알려 줍니다: sexual, minors, copyright, real_person, other.
invalid_inputno참조 파일을 읽을 수 없거나 모델이 값을 거부했습니다. 메시지에 어떤 값인지 표시됩니다.
model_declinedno모델이 이미지나 영상을 만드는 대신 글로 답했습니다. 프롬프트에 결과물 자체를 구체적으로 묘사하세요.
reference_changedno참조 파일이 검사된 후 변경되었습니다. 다시 보내세요.
max_cost_exceededno실행할 수 있는 유일한 경로의 비용이 상한보다 높습니다.
model_busyyes모든 경로가 한도에 도달했습니다. 1분 후에 다시 시도하세요.
model_unavailableyes지금은 이 작업을 받을 수 있는 경로가 없습니다.
timeoutyes제때 결과를 반환한 경로가 없거나, max_wait_s이 지났습니다.
all_routes_failedyes모든 경로가 각 경로 쪽 사정으로 실패했습니다.

내부적으로는 바쁘거나 문제가 있는 경로를 만난 작업이 자동으로 다음 경로로 넘어갑니다. 따라서 model_busy 또는 all_routes_failed가 보일 때는 이미 모든 경로를 시도한 상태입니다. attempts 필드에 시도한 횟수가 나옵니다. 보통 1~2분 기다렸다가 다시 시도하면 충분합니다.

콘텐츠 거부

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초 길이의 480p Seedance 2.0 Fast 클립이며, 성공하면 $0.25이고 실패하면 무료입니다. max_cost_usd 상한은 잘못된 설정으로 예상보다 많은 비용이 나가는 것을 막아 줍니다.

애초에 오류를 피하는 방법

  • 보내기 전에 옵션을 확인하세요. GET /v1/models와 모델 페이지에 모든 모델의 크기, 길이, 참조 제한이 나와 있습니다. 이 범위를 벗어난 값은 422 invalid_input와 함께 즉시 거부됩니다.
  • 파일은 포함하지 말고 업로드하세요. POST /v1/uploads는 최대 30 MB의 이미지, 50 MB의 영상, 15 MB의 오디오를 받고 14일간 유효한 링크를 반환하므로 요청 본문을 작게 유지할 수 있습니다.
  • 코드에서 잔액을 확인하세요. 대량 배치 전에 GET /v1/balance를 호출하면 402 오류가 연달아 나는 것을 막을 수 있습니다. 크레딧 팩은 요금 페이지에 있습니다.

성공한 작업의 비용을 줄이는 방법은 AI 영상 API 비용 줄이는 방법을 참고하세요. 전체 오류 레퍼런스는 문서에 있으며, 직접 사용해 보려면 API 키를 받으세요.

자주 묻는 질문

AI 영상 생성이 실패하면 요금이 청구되나요?

아니요. 요청을 제출할 때 금액이 보류되고, 작업이 실패하면 사유와 관계없이 보류가 해제됩니다.

어떤 오류를 재시도해야 하나요?

제출 시에는 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부터 시작하는 선불 크레딧이며, 성공한 작업에만 청구됩니다.