calesthio/OpenMontage · error · ValueError
Kling video response contained no downloadable URL: {item}
Error message
Kling video response contained no downloadable URL: {item} What it means
Raised by the static helper `_output_url(item)` when a single output object from the Kling response contains none of the known URL fields. The helper tries `url`, `video_url`, `resource_url` at the top level, then a nested `resource dict with a `url` key. If all are absent the item is un-downloadable and the raw item dict is embedded in the error so the developer can see exactly what shape came back.
Source
Thrown at tools/video/kling_official_video.py:621
base_path = Path(inputs.get("output_path", "kling_official_video.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 video response contained no downloadable URL: {item}")
@staticmethod
def _reference_metadata_from_classic_payload(payload: dict[str, Any]) -> list[dict[str, Any]]:
references: list[dict[str, Any]] = []
if payload.get("image"):
references.append({"kind": "image", "source_type": "reference_image"})
if payload.get("image_tail"):
references.append({"kind": "image", "source_type": "reference_tail_image"})
if payload.get("element_list"):
references.extend(
{"kind": "element", "element_id": item["element_id"]}
for item in normalize_element_list(payload.get("element_list"))
)
return references
@staticmethod
def _callback_result_data(inputs: dict[str, Any], task_id: str) -> dict[str, Any]:
callback_url = inputs.get("callback_url")View on GitHub (pinned to 95e1c3d0ab)
Solutions
- Print the `item` dict from the error message and identify which field actually carries the URL
- If the shape is a legitimate new Kling field, extend `_output_url` with one more `item.get(...)` fallback in the chain
- Filter outputs to only completed works before download, so in-progress/empty shells never reach this helper
- Re-query the task once after a short delay if the item indicates processing rather than a final artifact
Example fix
// before
url = item.get("url") or item.get("video_url") or item.get("resource_url")
// after (extend for new provider field)
url = (
item.get("url")
or item.get("video_url")
or item.get("resource_url")
or item.get("download_url")
) Defensive patterns
Strategy: type-guard
Validate before calling
KNOWN_URL_KEYS = ("url", "video_url", "resource_url")
def extract_output_url(item: dict) -> str | None:
for k in KNOWN_URL_KEYS:
if item.get(k):
return str(item[k])
res = item.get("resource")
if isinstance(res, dict) and res.get("url"):
return str(res["url"])
return None Type guard
def has_downloadable_url(item: dict) -> bool:
return bool(
item.get("url") or item.get("video_url") or item.get("resource_url")
or (isinstance(item.get("resource"), dict) and item["resource"].get("url"))
) Try / catch
try:
url = tool._output_url(item)
except ValueError:
logger.error("unrecognized output item shape: %s", item)
raise Prevention
- Filter the outputs list with has_downloadable_url before calling download
- Pin and monitor the Kling API version you build against; add regression fixtures with real response shapes
- Log the raw item on failure — the error already embeds it, so capture it in your error tracker
When it happens
Trigger: Kling returns an output item with a new/renamed field (e.g. `download_url`) not in the fallback chain; an item is a status/progress object accidentally mixed into the outputs list; the item contains only a task reference with the video still processing.
Common situations: Upstream API version drift adding new response shapes; polling code that feeds the whole task list rather than only completed works into `_download_videos`; content moderation or region flags that suppress the URL field without a clear error status.
Related errors
- Kling video response contained no downloadable URL: {outputs
- Kling image response item contained no downloadable URL: {it
- Completed but no video_url in output: {data}
- video_list items must be objects
- Kling video response contained no videos
AI-assisted analysis of calesthio/OpenMontage@95e1c3d0ab (2026-08-15).
Data as JSON: /api/errors/6fce05f34dc651b3.
Report an issue: GitHub.