ATH-MaaS/Pixelle-Video · error · RuntimeError
Seedance 任务成功但未返回视频 URL: {data}
Error message
Seedance 任务成功但未返回视频 URL: {data} What it means
_poll_until_done raises RuntimeError when the polled task reports status 'succeeded' but neither data['content']['video_url'] nor data['video_url'] contains a URL. Success without a downloadable URL is treated as a fatal inconsistency.
Source
Thrown at pixelle_video/services/api_services/video_seedance.py:158
raise RuntimeError(f"Seedance API 未返回任务 ID: {data}")
return task_id
def _poll_until_done(self, task_id: str, max_polls: int = 120, interval: int = 5) -> str:
# 同步更新查询接口路径
url = f"{self.base_url}/contents/generations/tasks/{task_id}"
for i in range(max_polls):
resp = requests.get(url, headers=self._headers(), timeout=30, proxies=self._proxies())
resp.raise_for_status()
data = resp.json()
status = data.get("status")
if status == "succeeded":
# 根据实际返回体,URL 位于 content.video_url 或 video_url
video_url = data.get("content", {}).get("video_url") or data.get("video_url")
if not video_url:
raise RuntimeError(f"Seedance 任务成功但未返回视频 URL: {data}")
return video_url
elif status in ("failed", "expired"):
error_msg = data.get("error", {}).get("message") or data.get("status_msg") or "未知错误"
raise RuntimeError(f"Seedance 视频生成{status}: {error_msg}")
logger.debug(f"SeedanceVideoClient: 任务进行中 {task_id}, status={status}, poll={i+1}")
time.sleep(interval)
raise TimeoutError(f"Seedance 视频生成超时 (task_id={task_id})")
def _download_video(self, url: str, save_path: str):
os.makedirs(os.path.dirname(save_path), exist_ok=True)
resp = requests.get(url, stream=True, timeout=120, proxies=self._proxies())
resp.raise_for_status()
with open(save_path, "wb") as f:
for chunk in resp.iter_content(chunk_size=8192):
if chunk:
f.write(chunk)View on GitHub (pinned to 848b054e4f)
Solutions
- Inspect the full data payload in the error message and locate where the video URL actually lives
- Add fallbacks for alternate shapes, e.g. data['content']['video_url'] list vs string, data['output']['video_url']
- Confirm the model name passed to generate_video returns videos (not images) for this endpoint
- Check for API changelog/version drift between your client and the deployed Seedance API
Example fix
// before
video_url = data.get("content", {}).get("video_url") or data.get("video_url")
// after
content = data.get("content") or {}
vu = content.get("video_url") or data.get("video_url")
if isinstance(vu, list):
vu = vu[0].get("url") if vu else None
if isinstance(vu, dict):
vu = vu.get("url") Defensive patterns
Strategy: try-catch
Type guard
def extract_video_url(data: dict) -> str | None:
vu = (data.get("content") or {}).get("video_url") or data.get("video_url")
if isinstance(vu, list):
vu = vu[0] if vu else None
if isinstance(vu, dict):
vu = vu.get("url")
return vu if isinstance(vu, str) and vu else None Try / catch
try:
video = client.generate_video(prompt=p, image_path=img, save_path=out)
except RuntimeError as e:
if "未返回视频 URL" in str(e):
logging.error(f"Seedance success payload malformed: {e}") # adapt client to new schema
else:
raise Prevention
- Inspect real success payloads and update URL-extraction fallbacks when the API evolves
- Pin the model name and test it after any API version bump
- Keep a schema smoke-test that polls a tiny task and asserts a URL is returned
When it happens
Trigger: Polling GET /contents/generations/tasks/{task_id} returns status=='succeeded' with an empty or differently-shaped result payload (no video_url under content or top level).
Common situations: API response schema changed (e.g. URL moved to output.video_url or a list of results); content generation produced an empty result; response truncated or proxied; using an incompatible model whose success payload differs.
Related errors
- Seedance API 未返回任务 ID: {data}
- frame_template is required to determine media size
- str(e)
- Video file not found: {video_path}
- Image edit failed: {response.code}, {response.message}, stat
AI-assisted analysis of ATH-MaaS/Pixelle-Video@848b054e4f (2026-08-30).
Data as JSON: /api/errors/9b3e8d8c6a549528.
Report an issue: GitHub.