calesthio/OpenMontage · error · ValueError
Kling avatar response item contained no downloadable URL: {i
Error message
Kling avatar response item contained no downloadable URL: {item} What it means
ValueError from KlingAvatarTool._output_url when a single result item carries no downloadable URL. The helper tries url, video_url, resource_url, then resource.url; if all are absent the item is undownloadable and the whole item (with its JSON) is embedded in the error for diagnosis. It indicates schema drift or a degenerate output entry rather than a user mistake.
Source
Thrown at tools/avatar/kling_avatar.py:304
base_path = Path(inputs.get("output_path", "kling_avatar.mp4"))
paths: list[Path] = []
for index, item in enumerate(outputs):
url = self._output_url(item)
suffix = extension_from_url(url, ".mp4")
output_path = numbered_output_path(output_path_with_suffix(base_path, suffix), index, suffix)
client.download(url, output_path)
paths.append(output_path)
return paths
@staticmethod
def _output_url(item: dict[str, Any]) -> str:
url = item.get("url") or item.get("video_url") or item.get("resource_url")
if url:
return str(url)
resource = item.get("resource") or {}
if isinstance(resource, dict) and resource.get("url"):
return str(resource["url"])
raise ValueError(f"Kling avatar response item contained no downloadable URL: {item}")
@staticmethod
def _copy_common_task_fields(inputs: dict[str, Any], payload: dict[str, Any]) -> None:
callback_url = validate_callback_url(inputs.get("callback_url"))
if callback_url:
payload["callback_url"] = callback_url
if inputs.get("external_task_id"):
payload["external_task_id"] = inputs["external_task_id"]
@staticmethod
def _callback_result_data(inputs: dict[str, Any], task_id: str) -> dict[str, Any]:
callback_url = inputs.get("callback_url")
if not callback_url:
return {}
return {
"callback_url": str(callback_url),
"callback_requested": True,
"polling_used": True,View on GitHub (pinned to 95e1c3d0ab)
Solutions
- Read the item JSON in the error message — it shows exactly which keys the entry has.
- Add the actual key to the fallback chain in _output_url.
- If the entry is not a video object (no URL of any kind), filter such entries out before download and check the task's status fields for the real failure.
Example fix
// before
url = item.get("url") or item.get("video_url") or item.get("resource_url")
// after
url = (
item.get("url")
or item.get("video_url")
or item.get("resource_url")
or item.get("video_result", {}).get("url")
) Defensive patterns
Strategy: type-guard
Validate before calling
def output_url(item: dict) -> str | None:
url = item.get("url") or item.get("video_url") or item.get("resource_url")
if not url:
resource = item.get("resource") or {}
url = resource.get("url") if isinstance(resource, dict) else None
return str(url) if url else None Type guard
def has_downloadable_url(item: dict) -> bool:
return output_url(item) is not None Try / catch
urls = [output_url(i) for i in outputs]
if any(u is None for u in urls):
log.warning("schema drift in avatar outputs: %s", outputs) Prevention
- Filter result items through a URL-extraction helper before download
- Log unrecognized item shapes to catch gateway schema drift on day one
When it happens
Trigger: Kling returns video entries where the URL sits under a new key (e.g. video_result.url or data.url) not covered by the fallback chain; an entry is a status/metadata object rather than a video object.
Common situations: Gateway firmware/API version changing the response field names; mixing responses from different Kling endpoints through the same downloader.
Related errors
- Kling TTS response contained no audios
- Kling TTS response item contained no downloadable URL: {item
- Kling avatar requires image_url or image_path
- mode must be one of: {', '.join(AVATAR_MODES)}
- Kling avatar requires audio_id, sound_file, sound_file_url,
AI-assisted analysis of calesthio/OpenMontage@95e1c3d0ab (2026-08-15).
Data as JSON: /api/errors/9aa826258475194c.
Report an issue: GitHub.