工作原理

AI 视频 API 错误码:含义与重试时机

视频生成任务比普通 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 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 值得带退避地重试;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 秒、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 起,仅对成功的任务收费。