Seedance 的报错分两层:一层是 HTTP 请求失败,例如 401、403、400、429;另一层是请求成功但任务最终 failed 或 expired。只看提交接口返回 200 就认为成功,是接入视频 API 时最常见的误判。正确的排查顺序是:先看 HTTP 状态码,再看任务状态和 error 字段,最后才改提示词或换模型。
本文按错误类型拆开,给出原因、处理顺序和一段可复用的错误处理代码。接口路径、状态命名和额度口径可能随版本调整,实际以站内文档和官方文档为准。
说明:Seedance、豆包、火山引擎是字节跳动及其关联公司的商标。本文仅作技术说明,不代表任何隶属或背书关系。示例中的路径和字段仅用于演示,调用前请核对文档。
一、先分清请求失败与任务失败
| 现象 | 所在层 | 常见原因 | 处理 |
|---|---|---|---|
| 401 | HTTP | Key 缺失、格式错误、已失效 | 修鉴权 |
| 403 | HTTP | 权限不足、模型未开通、区域限制 | 查权限与开通状态 |
| 400 | HTTP | 参数越界、模型名错误、素材不可访问 | 对照文档改参数 |
| 429 | HTTP | 并发、速率或配额受限 | 退避、降并发 |
| 5xx | HTTP | 上游过载或临时故障 | 退避、切通道 |
| failed | 任务 | 审核拒绝、素材问题、生成异常 | 读 error,修素材 |
| expired | 任务 | 超时未完成或未取结果 | 重建任务、检查期限 |
| 下载失败 | 结果 | URL 过期、鉴权、网络 | 重新获取或转存 |
日志至少记录时间、HTTP 状态码、错误码、模型名、task_id、业务单号和耗时。不要记录完整 Key,也不要把带签名的结果 URL 原样打印。
二、401 与 403:先查请求头和 Key
401 表示身份没有通过验证,通常和模型能力、余额无关。按顺序检查:
Authorization是否为Bearer <key>,火山方舟使用 API Key 作为 Bearer Token。- Key 是否带空格、换行或多余引号,环境变量是否真的加载。
- Base URL 与 Key 是否属于同一平台、同一区域。
- Key 是否被删除、轮换、停用,或项目权限不足。
- 反向代理是否覆盖或丢弃了
Authorization头。
403 更多是权限问题:模型未开通、账号没有该模型权限、区域或合规限制。401 换一把新 Key 做最小请求即可快速定位;403 要查控制台的开通状态和账号权限,改代码通常无效。
三、429:限流、并发与配额
429 表示请求超过速率、并发或配额限制。常见触发场景:
- 多个服务共用一把 Key,互相挤占额度。
- 批量任务在整点同时启动,形成流量脉冲。
- 重试没有退避,越失败越发,形成重试风暴。
- 长任务占满并发,短任务也排不进去。
处理原则是指数退避加随机抖动、降低并发、按项目拆 Key、错峰提交。不要在没有退避的情况下循环重试;429 期间继续高频提交,会把限流拖成持续故障。业务确实需要高并发时,提前确认配额上限,并准备备用通道。
四、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:必须能被平台访问,不能是内网地址或需要登录的链接。
- 编辑或续写任务:部分模式只允许自动时长,不能手填秒数。
- 音频输入:部分版本不支持纯音频输入。
最省时间的做法是用文档示例请求体做最小复现,再逐项加回自己的参数。每加一项测一次,就能定位到具体字段。
五、任务 failed 与 expired
提交成功只代表任务入队。查询结果里常见状态包括 queued、running、succeeded、failed、expired。failed 要看 error 字段:内容审核拒绝、输入素材不合规、参考图无法读取、生成过程异常,处理方式完全不同。
expired 常见于任务超过执行期限仍未完成或未取回结果。文档中 execution_expires_after 可配置,默认 48 小时;任务 ID 保留 7 天。超过期限后继续轮询不会恢复,只能重建任务。使用回调时还要注意:回调未在 5 秒内确认会被重试 3 次,回调接口必须幂等。
审核拒绝不要靠改几个词反复绕过。先确认素材授权、人物肖像、品牌元素和内容政策,再决定是否重提。
六、超时与轮询
超时要分三层:客户端连接超时、单次查询超时、任务总 deadline。提交接口通常很快返回 task_id,真正耗时的是排队和渲染。HTTP 客户端超时设得过短,会把正常提交误判为失败;设得过长,又会拖住线程池。
轮询建议从 5 秒起步,逐步退避到 15–30 秒,并设置总 deadline。支持回调时优先用回调,轮询作为兜底。不要在超时后立刻重复提交,先用业务单号或幂等键检查是否已有任务在运行。
七、结果下载失败
任务成功不等于文件到手。video_url 往往是带签名的临时地址,有有效期;直接存库、几小时后再下载,常见 403 或 404。处理方式:
- 成功后立即流式下载到自己的对象存储。
- 下载失败单独重试,不要重建生成任务。
- 校验 Content-Type、文件大小和可播放性。
- 日志里不要打印完整签名 URL。
八、示例:带退避与幂等的错误处理
下面的代码把提交、轮询和下载分开处理,只对瞬时错误重试。路径与字段以站内文档为准。
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。参数错误和鉴权错误重试多少次都不会成功,只会放大日志和费用。
九、重试、幂等与支持清单
重试只适合瞬时错误:429、5xx、连接超时。400、401、403 和审核拒绝不应自动重试。幂等的关键不是重试次数,而是业务单号:提交前查任务表,提交后落库 task_id,重复请求复用已有任务。
联系服务方前,按下面的清单整理信息:
- 记录发生时间、HTTP 状态码、错误码和完整错误信息,注意脱敏。
- 记录模型名、时长、分辨率、比例和参考素材数量。
- 记录 task_id、业务单号、提交次数和轮询次数。
- 保留一条最小复现请求,去掉用户隐私和密钥。
- 区分请求失败与任务 failed 或 expired。
- 检查素材 URL 是否可公开访问、响应是否过慢。
- 确认配额、并发和账号权限,排除 429 与 403。
- 附上请求 ID 和复现时间,再提交排查。
常见问题
提交接口返回 200,为什么任务还是失败?
200 只代表任务创建成功。视频生成是异步的,最终状态要看查询结果里的 status 和 error 字段。
429 是不是余额不足?
不一定。429 通常表示速率、并发或配额受限,余额问题可能返回其他错误。先查并发、共享 Key 和重试策略。
任务 failed 后能直接重试吗?
先读 error。审核拒绝和素材不合规,原样重试通常还会失败;网络或上游故障可以退避重试。重试前用业务单号做幂等检查。
轮询多久一次合适?
从 5 秒起步,逐步退避到 15–30 秒,并设置总超时。支持回调时优先用回调,轮询作为兜底。
结果 URL 打不开怎么办?
多数是有效期过期或签名失效。成功后应立即转存对象存储;已经过期则重新查询任务或重建任务,不要反复请求旧链接。
下一步
先在中商起航 AI 网关创建测试 Key,把 401、429、参数错误和任务失败各演练一次,确认告警和重试策略生效。模型可用性与计费方式以模型价格为准。
相关阅读:
