TROUBLESHOOTING · ERROR FAQ
Video Generation API Timeouts: Async Polling Done Right
Video generation is not a request-response call — a 5-to-8-second clip takes 30 seconds to several minutes of server time, and your client architecture has to treat that as normal. Most "the API timed out" reports decompose into three causes: queueing delay, genuinely slow generation, or a poll interval your own code configured badly. This page covers how to tell them apart, the polling loop design that handles all three (interval backoff, wall-clock cap, terminal-state discipline), the webhook that removes polling entirely, and why a timeout is not a failure — which matters for billing. Companion pages: error triage and the 200-but-error trap.
Why video is naturally long-running
A text request streams tokens as they're produced; a video request must fully render every frame before any of it can be delivered. Median latencies run from ~30 seconds for short clips to several minutes for higher tiers, plus queue wait during peak hours. Any client timeout under a few minutes will fire on healthy tasks. Set expectations from the model page — e.g. Veo 3.1 8-second clips — before tuning anything.
The three culprits
- Queueing: your task is queued behind others. Symptom: status stays "queued", then jumps to completed quickly once running. Fix: nothing client-side; just don't abort.
- Slow generation: task is in_progress the whole time and completes late. Symptom: long in_progress phase, healthy completion. Fix: raise the wall-clock budget; consider faster tiers for non-hero content.
- Poll-interval misconfiguration: your code polls too fast (rate-limited, or burns quota), or treats a single failed poll as task failure. Symptom: errors on the poll endpoint while the task itself succeeds. Fix: the loop below.
The polling loop: backoff, cap, terminal states
The three disciplines: backoff the poll interval (start ~3s, grow ~1.6x, cap ~15s), cap total wall-clock time and treat breach as its own condition, and exit only on explicit terminal states — never on a failed poll request or a long silence.
import time
MAX_SECONDS = 600 # wall-clock cap: generous for 5-8s clips
interval, deadline = 3.0, time.time() + MAX_SECONDS
while time.time() < deadline:
task = get_task(task_id) # GET /v1/videos/{task_id}
if task["status"] == "completed":
return task["url"] # result URL is the top-level url field
if task["status"] == "failed": # terminal — exit with the code
raise TaskFailed(task["error"]["code"])
interval = min(interval * 1.6, 15.0) # backoff, capped
time.sleep(interval)
raise TaskTimeout(task_id) # timeout ≠ failure: see below The webhook alternative
Register a callback URL at submit and the terminal state is pushed to you — no polling loop, no interval tuning, no timeout heuristics. Webhooks are free in every tier on ModAPIS. Keep a low-frequency poll (say every 60s) as a fallback for missed deliveries, and make the webhook authoritative for completion to avoid duplicate-generation races with a retry loop.
Timeout is not failure: state machine and billing
Your client's wall-clock deadline expiring says nothing about the server-side task, which may still succeed five seconds later — which is why idempotency keys matter on any resubmit. Billing follows the task's terminal state, not your patience: tasks ending in FAILURE are not charged on ModAPIS, in any tier. A timed-out-but-completed task is a delivery problem, not a billing one; a failed task is closed with its error code. The triage table for those codes is in the Veo error guide; first request in five minutes via the quickstart.