ATH-MaaS/Pixelle-Video · error · TimeoutError

Seedance 视频生成超时 (task_id={task_id})

Error message

Seedance 视频生成超时 (task_id={task_id})

What it means

_poll_until_done raises TimeoutError after exhausting max_polls (default 120) polling attempts at interval seconds (default 5) without the task reaching 'succeeded' or 'failed'. The task is still pending server-side when the client gives up.

Source

Thrown at pixelle_video/services/api_services/video_seedance.py:167

            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)
        logger.info(f"SeedanceVideoClient: 视频已保存: {save_path}")

if __name__ == "__main__":
    import sys
    sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
    from config import Config

    logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")

View on GitHub (pinned to 848b054e4f)

Solutions

  1. Increase the polling budget via _poll_until_done(task_id, max_polls=..., interval=...) or expose it through generate_video kwargs
  2. Then poll the task ID manually — the exception includes task_id, and the task may still finish later
  3. Increase the interval (e.g. 10s) to reduce API pressure on long jobs
  4. Check service status for Seedance/Ark outages before retrying

Example fix

// before
video_url = self._poll_until_done(task_id)
// after
video_url = self._poll_until_done(task_id, max_polls=360, interval=10)
Defensive patterns

Strategy: retry

Try / catch

try:
    video = client.generate_video(prompt=p, image_path=img, save_path=out)
except TimeoutError as e:
    task_id = str(e).split("task_id=")[-1].rstrip(")")
    logging.warning(f"Generation still running; resume polling {task_id} manually")
    # continue polling via the task-query endpoint instead of resubmitting

Prevention

When it happens

Trigger: generate_video submits a task whose generation takes longer than max_polls*interval (default 10 minutes) — typical with long durations, high resolution, or peak-time queueing.

Common situations: Long-duration/high-res generation; service degraded/slow queue; interval too aggressive causing throttle responses that never advance status; task silently stuck in 'running'.

Related errors


AI-assisted analysis of ATH-MaaS/Pixelle-Video@848b054e4f (2026-08-30). Data as JSON: /api/errors/68986372e828c920. Report an issue: GitHub.