{"record":{"id":"826586203e0508e9","repo":"calesthio/OpenMontage","slug":"heygen-execution-execution-id-timed-out-after-t","errorCode":null,"errorMessage":"HeyGen execution {execution_id} timed out after {timeout}s","messagePattern":"HeyGen execution (.+?) timed out after (.+?)s","errorType":"exception","errorClass":"TimeoutError","httpStatus":null,"severity":"error","filePath":"tools/video/_shared.py","lineNumber":415,"sourceCode":"        data = response.json().get(\"data\", {})\n        status = data.get(\"status\", \"\")\n\n        if status == \"completed\":\n            video_url = (\n                data.get(\"output\", {}).get(\"video\", {}).get(\"video_url\")\n                or data.get(\"output\", {}).get(\"video_url\")\n            )\n            if video_url:\n                return video_url\n            raise RuntimeError(f\"Completed but no video_url in output: {data}\")\n\n        if status in {\"failed\", \"error\"}:\n            raise RuntimeError(f\"HeyGen generation failed: {data.get('error', 'Unknown')}\")\n\n        time.sleep(min(interval, max(0.0, deadline - time.time())))\n        interval = min(interval * 1.2, 30.0)\n\n    raise TimeoutError(f\"HeyGen execution {execution_id} timed out after {timeout}s\")\n\n\ndef upload_image_fal(image_path: str) -> str:\n    \"\"\"Upload a local image to fal.ai storage and return a public URL.\"\"\"\n    import requests\n\n    api_key = os.environ.get(\"FAL_KEY\") or os.environ.get(\"FAL_AI_API_KEY\")\n    if not api_key:\n        raise RuntimeError(\"FAL_KEY or FAL_AI_API_KEY required for image upload\")\n\n    path = Path(image_path)\n    if not path.exists():\n        raise FileNotFoundError(f\"Image not found: {image_path}\")\n\n    suffix = path.suffix.lower()\n    content_type = {\"png\": \"image/png\", \"jpg\": \"image/jpeg\", \"jpeg\": \"image/jpeg\", \"webp\": \"image/webp\"}.get(\n        suffix.lstrip(\".\"), \"image/png\"\n    )","sourceCodeStart":397,"sourceCodeEnd":433,"githubUrl":"https://github.com/calesthio/OpenMontage/blob/95e1c3d0ab93482159818560f6a8c8e866b9139f/tools/video/_shared.py#L397-L433","documentation":"Raised as TimeoutError when the HeyGen execution poller exhausts its timeout budget (poll interval grows from a base via *1.2 backoff, capped at 30s) without the status becoming completed/failed/error. HeyGen renders can simply take longer than the configured timeout, especially for long multi-scene videos, so this is a client-side give-up, not a server-side failure.","triggerScenarios":"Rendering a multi-minute multi-scene video with a short timeout; HeyGen under heavy load with slow queue times; conservative timeout defaults (often far below real render durations for Video Agent jobs).","commonSituations":"Prompt-to-video agent jobs that take 5-15+ minutes while the caller allowed 2-3; peak-load days; 4K or many-scene compositions.","solutions":["Increase the timeout parameter passed to the poll/exec call — HeyGen Video Agent jobs routinely need 10+ minutes","Before assuming failure, GET the execution once more by id: it often completed after the caller gave up; reuse that URL instead of resubmitting (and paying) again","Reduce scene count / video length if timeouts are budget-constrained","Wrap with retry that first checks execution status by id, resubmitting only if actually failed"],"exampleFix":"# before\nvideo_url = wait_for_video(execution_id, timeout=180)\n# after\nvideo_url = wait_for_video(execution_id, timeout=900)  # 15 min for long jobs","handlingStrategy":"retry","validationCode":"null","typeGuard":null,"tryCatchPattern":"try:\n    url = wait_for_video(execution_id, timeout=900)\nexcept TimeoutError:\n    # poll once more by id: job frequently completed after give-up\n    data = fetch_execution(execution_id)\n    if data.get(\"status\") == \"completed\":\n        return extract_video_url(data)\n    raise","preventionTips":["Scale timeout to job size (multi-scene Video Agent: 10+ minutes)","Always keep the execution_id so a post-timeout status check can recover the asset without rebilling","Use exponential poll intervals to reduce API pressure on long jobs"],"tags":["heygen","timeout","polling","video-generation"],"backgroundTag":null,"analyzedSha":"95e1c3d0ab93482159818560f6a8c8e866b9139f","analyzedAt":"2026-08-15T06:31:20.014Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}