calesthio/OpenMontage · error · RuntimeError
Kling result did not include a remote video URL for lip-sync
Error message
Kling result did not include a remote video URL for lip-sync input.
What it means
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.
Source
Thrown at scripts/kling_official_animated_explainer_e2e.py:470
"estimated_cost_usd": sum(
float(getattr(result, "cost_usd", 0) or 0)
for result in (image_result, video_result)
)
+ float(tts_data.get("estimated_cost_usd") or 0),
}
def _first_remote_url(result_data: dict[str, Any]) -> str:
direct = result_data.get("remote_url")
if direct:
return str(direct)
for item in result_data.get("remote_outputs") or []:
if not isinstance(item, dict):
continue
url = item.get("url") or item.get("video_url") or item.get("resource_url")
if url:
return str(url)
raise RuntimeError("Kling result did not include a remote video URL for lip-sync input.")
def _run_live_avatar_suite(
project_dir: Path,
*,
timeout_seconds: int,
poll_interval: float,
) -> dict[str, Any]:
image = registry.get("image_selector")
avatar = registry.get("kling_avatar")
lip_sync = registry.get("kling_lip_sync")
assert image and avatar and lip_sync
assets_dir = project_dir / "assets"
image_dir = assets_dir / "images"
video_dir = assets_dir / "video"
artifacts_dir = project_dir / "artifacts"
narration_path = assets_dir / "audio" / "narration.mp3"View on GitHub (pinned to 95e1c3d0ab)
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
Example fix
# before
for item in result_data.get("remote_outputs") or []:
url = item.get("url") or item.get("video_url") or item.get("resource_url")
# after (also accept Kling works[] shape)
for item in (result_data.get("remote_outputs")
or ((result_data.get("data") or {}).get("task_result") or {}).get("works")
or []):
url = item.get("url") or item.get("video_url") or item.get("resource_url") Defensive patterns
Strategy: type-guard
Validate before calling
def has_remote_url(result_data: dict) -> bool:
if result_data.get("remote_url"):
return True
return any(
isinstance(i, dict) and (i.get("url") or i.get("video_url") or i.get("resource_url"))
for i in result_data.get("remote_outputs") or []
)
if not has_remote_url(result_data):
raise SystemExit("no remote URL in result; inspect payload before lip-sync") Type guard
def extract_remote_url(result_data: dict) -> str | None:
if result_data.get("remote_url"):
return str(result_data["remote_url"])
for item in result_data.get("remote_outputs") or []:
if isinstance(item, dict):
u = item.get("url") or item.get("video_url") or item.get("resource_url")
if u:
return str(u)
return None Try / catch
url = extract_remote_url(result_data)
if url is None:
print(json.dumps(result_data, indent=2)) # schema drift diagnostics
raise SystemExit("kling result schema lacks a remote video URL") Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- {name} failed: {result.error}
- Avatar smoke requires an existing narration file: {narration
- Kling Classic create response missing data.task_id: {data}
- Kling Classic result path data.task_result.{result_key} is n
- Kling image response item contained no downloadable URL: {it
AI-assisted analysis of calesthio/OpenMontage@95e1c3d0ab (2026-08-15).
Data as JSON: /api/errors/7c0137fec389a569.
Report an issue: GitHub.