{"record":{"id":"516a3ef0a1d7fbf6","repo":"calesthio/OpenMontage","slug":"heygen-generation-failed-data-get-error-unkn","errorCode":null,"errorMessage":"HeyGen generation failed: {data.get('error', 'Unknown')}","messagePattern":"HeyGen generation failed: (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"tools/video/_shared.py","lineNumber":410,"sourceCode":"    interval = 5.0\n\n    while time.time() < deadline:\n        response = requests.get(url, headers=headers, timeout=30)\n        response.raise_for_status()\n        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}\")","sourceCodeStart":392,"sourceCodeEnd":428,"githubUrl":"https://github.com/calesthio/OpenMontage/blob/95e1c3d0ab93482159818560f6a8c8e866b9139f/tools/video/_shared.py#L392-L428","documentation":"Raised in the HeyGen execution poller when the execution status is 'failed' or 'error'. The message embeds data['error'] when present, otherwise 'Unknown'. This is HeyGen reporting the generation itself failed — bad inputs (script, avatar, voice ids), moderation rejection, quota/billing, or an internal HeyGen error.","triggerScenarios":"Referencing a deleted avatar_id or voice_id; script with disallowed content; account out of credits; HeyGen internal error during render; malformed workflow payload accepted at submit but rejected at execution.","commonSituations":"Hard-coded avatar/voice ids that were removed from the workspace; expired HeyGen subscription; content moderation tripping on marketing copy with strong claims.","solutions":["Read the embedded error text — it names the actual cause","For invalid ids: list current avatars/voices via the HeyGen API and update inputs","For quota/billing: check the HeyGen dashboard before retrying","For internal errors: retry once — these are often transient"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"null","typeGuard":null,"tryCatchPattern":"try:\n    url = wait_for_video(execution_id)\nexcept RuntimeError as e:\n    err = str(e)\n    if \"quota\" in err or \"credit\" in err:\n        halt_and_alert_billing()\n    elif \"avatar\" in err or \"voice\" in err or \"not found\" in err:\n        inputs = refresh_avatar_voice_ids(inputs); resubmit()\n    else:\n        retry_once(inputs)  # internal errors are often transient\n    raise","preventionTips":["Resolve avatar/voice ids dynamically, never hard-code them","Check HeyGen credit balance before batch runs","Classify error text (quota/ids/moderation/internal) before retry decisions"],"tags":["heygen","video-generation","generation-failure","api-error"],"backgroundTag":null,"analyzedSha":"95e1c3d0ab93482159818560f6a8c8e866b9139f","analyzedAt":"2026-08-15T06:31:20.014Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}