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_id

View on GitHub (pinned to 1c6d8d45b3)

Solutions

  1. Retry the node; transient render/publish failures usually succeed on a new job (a fresh Idempotency-Key is generated per run)
  2. Simplify the payload (different avatar, default resolution) to rule out render-side rejection
  3. Check the video_id in the HeyGen dashboard for the detailed failure reason
  4. 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

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


AI-assisted analysis of Comfy-Org/ComfyUI@1c6d8d45b3 (2026-08-14). Data as JSON: /api/errors/3988ed7cf6293adc. Report an issue: GitHub.