{"record":{"id":"7c0137fec389a569","repo":"calesthio/OpenMontage","slug":"kling-result-did-not-include-a-remote-video-url-fo","errorCode":null,"errorMessage":"Kling result did not include a remote video URL for lip-sync input.","messagePattern":"Kling result did not include a remote video URL for lip-sync input\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"scripts/kling_official_animated_explainer_e2e.py","lineNumber":470,"sourceCode":"        \"estimated_cost_usd\": sum(\n            float(getattr(result, \"cost_usd\", 0) or 0)\n            for result in (image_result, video_result)\n        )\n        + float(tts_data.get(\"estimated_cost_usd\") or 0),\n    }\n\n\ndef _first_remote_url(result_data: dict[str, Any]) -> str:\n    direct = result_data.get(\"remote_url\")\n    if direct:\n        return str(direct)\n    for item in result_data.get(\"remote_outputs\") or []:\n        if not isinstance(item, dict):\n            continue\n        url = item.get(\"url\") or item.get(\"video_url\") or item.get(\"resource_url\")\n        if url:\n            return str(url)\n    raise RuntimeError(\"Kling result did not include a remote video URL for lip-sync input.\")\n\n\ndef _run_live_avatar_suite(\n    project_dir: Path,\n    *,\n    timeout_seconds: int,\n    poll_interval: float,\n) -> dict[str, Any]:\n    image = registry.get(\"image_selector\")\n    avatar = registry.get(\"kling_avatar\")\n    lip_sync = registry.get(\"kling_lip_sync\")\n    assert image and avatar and lip_sync\n\n    assets_dir = project_dir / \"assets\"\n    image_dir = assets_dir / \"images\"\n    video_dir = assets_dir / \"video\"\n    artifacts_dir = project_dir / \"artifacts\"\n    narration_path = assets_dir / \"audio\" / \"narration.mp3\"","sourceCodeStart":452,"sourceCodeEnd":488,"githubUrl":"https://github.com/calesthio/OpenMontage/blob/95e1c3d0ab93482159818560f6a8c8e866b9139f/scripts/kling_official_animated_explainer_e2e.py#L452-L488","documentation":"Raised by _first_remote_url when parsing a completed Kling video generation result. The helper looks for `remote_url` at the top level, then iterates `remote_outputs` for `url`/`video_url`/`resource_url` keys; if none is found it cannot build the input for the next pipeline stage (lip-sync needs a remote video URL) and raises. It almost always means the Kling API response schema changed or the result is structurally different from expected, not that generation failed.","triggerScenarios":"Running the avatar smoke suite (--live-avatar or the avatar stage of --live-full): a kling_official_video/avatar call succeeds, then _first_remote_url(result.data) is called to feed the video URL into kling_lip_sync, but the response dict contains neither remote_url nor a usable remote_outputs entry.","commonSituations":"Kling API schema drift (renamed output fields); the avatar tool returning only local file paths (already downloaded artifacts) with no remote references; a partially-truncated result dict logged from an earlier session being replayed; empty remote_outputs list on an asynchronous task queried too early.","solutions":["Print the full result_data dict and locate where the URL now lives (commonly under data.task_result.works[].resource_url in Kling responses)","Update _first_remote_url to also check the actual field path found in the response, or pass the tool's documented output accessor instead of raw data","Ensure the upstream result comes from a genuinely completed task (status succeeded), not a pending one polled early","If only local files exist, upload/serve the artifact and construct the lip-sync input from a hosted URL"],"exampleFix":"# before\nfor item in result_data.get(\"remote_outputs\") or []:\n    url = item.get(\"url\") or item.get(\"video_url\") or item.get(\"resource_url\")\n\n# after (also accept Kling works[] shape)\nfor item in (result_data.get(\"remote_outputs\")\n             or ((result_data.get(\"data\") or {}).get(\"task_result\") or {}).get(\"works\")\n             or []):\n    url = item.get(\"url\") or item.get(\"video_url\") or item.get(\"resource_url\")","handlingStrategy":"type-guard","validationCode":"def has_remote_url(result_data: dict) -> bool:\n    if result_data.get(\"remote_url\"):\n        return True\n    return any(\n        isinstance(i, dict) and (i.get(\"url\") or i.get(\"video_url\") or i.get(\"resource_url\"))\n        for i in result_data.get(\"remote_outputs\") or []\n    )\nif not has_remote_url(result_data):\n    raise SystemExit(\"no remote URL in result; inspect payload before lip-sync\")","typeGuard":"def extract_remote_url(result_data: dict) -> str | None:\n    if result_data.get(\"remote_url\"):\n        return str(result_data[\"remote_url\"])\n    for item in result_data.get(\"remote_outputs\") or []:\n        if isinstance(item, dict):\n            u = item.get(\"url\") or item.get(\"video_url\") or item.get(\"resource_url\")\n            if u:\n                return str(u)\n    return None","tryCatchPattern":"url = extract_remote_url(result_data)\nif url is None:\n    print(json.dumps(result_data, indent=2))  # schema drift diagnostics\n    raise SystemExit(\"kling result schema lacks a remote video URL\")","preventionTips":["Log full result payloads once per schema change so drift is visible","Prefer tool-level accessors over raw dict digging","Only feed completed (status=succeeded) results into lip-sync"],"tags":["kling","api-schema","parsing","e2e"],"backgroundTag":null,"analyzedSha":"95e1c3d0ab93482159818560f6a8c8e866b9139f","analyzedAt":"2026-08-15T06:31:20.014Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}