Comfy-Org/ComfyUI · error · ValueError
HeyGen returned no video_url for video {video_id}.
Error message
HeyGen returned no video_url for video {video_id}. What it means
Thrown when polling of a HeyGen video job reaches a terminal state but the final data object lacks video_url. The id existed and polling completed, yet the result payload is incomplete — typically a 'completed' job whose render artifact failed to publish, or a failed status the poller treated as final.
Source
Thrown at comfy_api_nodes/nodes_heygen.py:88
"""POST a /v3/videos payload, poll until terminal, and return the final video data."""
created = await sync_op_raw(
cls,
ApiEndpoint(path=_VIDEOS_PATH, method="POST", headers={"Idempotency-Key": uuid.uuid4().hex}),
data=payload,
)
video_id = (created.get("data") or {}).get("video_id")
if not video_id:
raise ValueError(f"HeyGen did not return a video_id: {created}")
final = await poll_op_raw(
cls,
ApiEndpoint(path=f"{_VIDEOS_PATH}/{video_id}"),
status_extractor=lambda r: (r.get("data") or {}).get("status"),
queued_statuses=["pending", "waiting"],
poll_interval=5.0,
)
data = final["data"]
if not data.get("video_url"):
raise ValueError(f"HeyGen returned no video_url for video {video_id}.")
return data
async def _resolve_avatar(
cls: type[IO.ComfyNode], avatar_label: str, custom_avatar_id: str, engine_choice: str
) -> tuple[str, str | None]:
"""Resolve (avatar_id, engine_type) from the combo/override + engine widgets."""
custom_avatar_id = custom_avatar_id.strip()
if custom_avatar_id:
look = (
await sync_op_raw(
cls,
ApiEndpoint(path=f"{_LOOKS_PATH}/{custom_avatar_id}"),
final_label_on_success=None,
)
).get("data") or {}
avatar_id = custom_avatar_id
avatar_label = look.get("name") or custom_avatar_idView on GitHub (pinned to 1c6d8d45b3)
Solutions
- Retry the node; transient render/publish failures usually succeed on a new job (a fresh Idempotency-Key is generated per run)
- Simplify the payload (different avatar, default resolution) to rule out render-side rejection
- Check the video_id in the HeyGen dashboard for the detailed failure reason
- If persistent across inputs, report upstream — video_id existed but no artifact was produced
Defensive patterns
Strategy: retry
Try / catch
for attempt in range(2):
try:
return await _create_and_poll_video(cls, payload)
except ValueError as e:
if 'no video_url' in str(e) and attempt == 0:
continue # transient render/publish failure; fresh idempotency key per run
raise Prevention
- Wrap HeyGen render calls in one retry — export-stage failures are usually transient
- Check the job id in the HeyGen dashboard when a retry also fails
When it happens
Trigger: poll_op_raw on GET /v3/videos/{video_id} returns data with no video_url; e.g. HeyGen marks the job failed or returns partial data after server-side render errors.
Common situations: HeyGen-side render failures (bad avatar/photo combination, unsupported resolution), transient CDN publishing issues, or jobs cancelled server-side.
Related errors
- HeyGen returned no video_url for translation {translation_id
- HeyGen did not return a video_id: {created}
- HeyGen did not return a translation ID: {created}
- A voice is required when driving the video with a text scrip
- Avatar '{avatar_label}' does not support the {engine} engine
AI-assisted analysis of Comfy-Org/ComfyUI@1c6d8d45b3 (2026-08-14).
Data as JSON: /api/errors/3988ed7cf6293adc.
Report an issue: GitHub.