calesthio/OpenMontage · error · RuntimeError
Completed but no video_url in output: {data}
Error message
Completed but no video_url in output: {data} What it means
Raised in the HeyGen execution poller when status is 'completed' but neither data.output.video.video_url nor data.output.video_url exists. HeyGen marked the execution done yet returned a payload the extractor cannot read, so there is no URL to download. Typically a response-shape variant (URL nested elsewhere, e.g. under output.video.url_list) or an empty completion.
Source
Thrown at tools/video/_shared.py:407
headers = {"X-Api-Key": api_key}
url = f"https://api.heygen.com/v1/workflows/executions/{execution_id}"
deadline = time.time() + timeout
interval = 5.0
while time.time() < deadline:
response = requests.get(url, headers=headers, timeout=30)
response.raise_for_status()
data = response.json().get("data", {})
status = data.get("status", "")
if status == "completed":
video_url = (
data.get("output", {}).get("video", {}).get("video_url")
or data.get("output", {}).get("video_url")
)
if video_url:
return video_url
raise RuntimeError(f"Completed but no video_url in output: {data}")
if status in {"failed", "error"}:
raise RuntimeError(f"HeyGen generation failed: {data.get('error', 'Unknown')}")
time.sleep(min(interval, max(0.0, deadline - time.time())))
interval = min(interval * 1.2, 30.0)
raise TimeoutError(f"HeyGen execution {execution_id} timed out after {timeout}s")
def upload_image_fal(image_path: str) -> str:
"""Upload a local image to fal.ai storage and return a public URL."""
import requests
api_key = os.environ.get("FAL_KEY") or os.environ.get("FAL_AI_API_KEY")
if not api_key:
raise RuntimeError("FAL_KEY or FAL_AI_API_KEY required for image upload")
View on GitHub (pinned to 95e1c3d0ab)
Solutions
- Log the full data dict from the exception message and locate where the URL actually lives
- Extend the extractor chain (video.video_url, video_url, url_list[0], video.url)
- If output is genuinely empty, re-run the generation
- Check HeyGen changelog for output schema changes on the v1/v2 execution endpoints
Example fix
// before
video_url = data.get("output", {}).get("video", {}).get("video_url") or data.get("output", {}).get("video_url")
// after
out = data.get("output", {}) or {}
video_url = (
(out.get("video") or {}).get("video_url")
or out.get("video_url")
or ((out.get("video") or {}).get("url_list") or [None])[0]
) Defensive patterns
Strategy: try-catch
Validate before calling
null
Try / catch
try:
url = wait_for_video(execution_id)
except RuntimeError as e:
if "no video_url" in str(e):
# one manual re-fetch: schema variants sometimes settle,
# otherwise inspect data for alternate URL keys
data = fetch_execution(execution_id)
url = deep_first_url(data) or requeue_generation()
raise Prevention
- Log completed-but-unparseable payloads whole; they encode the new schema
- Version-pin against HeyGen API change announcements
- Centralize the URL-extraction chain so one fix covers all callers
When it happens
Trigger: Video Agent finishes with a payload where the URL key differs (url_list, video_urls, or per-scene URLs); a completed execution whose output was purged or never attached; preview vs final asset split in newer API versions.
Common situations: HeyGen API evolution adding new output layouts; long-retention windows expiring outputs; executions that completed with zero scenes.
Related errors
- Kling image response item contained no downloadable URL: {it
- Seedream completed but no images returned
- HeyGen generation failed: {data.get('error', 'Unknown')}
- HeyGen execution {execution_id} timed out after {timeout}s
- Kling video response contained no downloadable URL: {item}
AI-assisted analysis of calesthio/OpenMontage@95e1c3d0ab (2026-08-15).
Data as JSON: /api/errors/a1f168c70752c789.
Report an issue: GitHub.