calesthio/OpenMontage · error · ValueError

Kling lip-sync response item contained no downloadable URL

Error message

Kling lip-sync response item contained no downloadable URL: {item}

What it means

Raised by KlingLipSyncTool._output_url when a single output item contains no URL under any known key: url, video_url, resource_url, or resource.url. The item exists but has no downloadable location, so the tool cannot fetch the rendered video. The message embeds the offending item for diagnosis.

Solutions

  1. Log the embedded item dict — it usually reveals the actual field name or a pending/expired status
  2. Wait for the task to be fully complete (not merely 'succeeded' at task level) before downloading, then retry
  3. If a new field name appears (e.g. 'download_url'), map it into item['url'] in your wrapper before the tool reads it, or patch _output_url and report upstream
Defensive patterns

Strategy: try-catch

Validate before calling

def item_has_url(item) -> bool:
    if item.get("url") or item.get("video_url") or item.get("resource_url"):
        return True
    r = item.get("resource")
    return isinstance(r, dict) and bool(r.get("url"))

bad = [i for i in outputs if not item_has_url(i)]
if bad:
    log.warning("output items without URLs: %s", bad)

Type guard

def item_has_url(item) -> bool:
    if item.get("url") or item.get("video_url") or item.get("resource_url"):
        return True
    r = item.get("resource")
    return isinstance(r, dict) and bool(r.get("url"))

Try / catch

try:
    url = extract_output_url(item)
except ValueError:
    log.warning("no URL in item; waiting and re-polling task: %s", item)
    outputs = client.wait_for_task(task_id, force_refresh=True).get("outputs", [])
    # re-attempt extraction once

Prevention

When it happens

Trigger: An outputs entry that only carries metadata (id, status, thumbnails) because the video asset is still processing or was purged; an upstream schema change introducing a new URL field name the tool does not know; an item whose resource is not a dict.

Common situations: Downloading too early after task completion; expired CDN links from a delayed download; Kling API version drift.

Related errors


AI-assisted analysis of calesthio/OpenMontage@95e1c3d0ab (2026-08-15). Data as JSON: /api/errors/f0352587d6a95d42. Report an issue: GitHub.

Appendix: source

Thrown at tools/avatar/kling_lip_sync.py:677

        base_path = Path(inputs.get("output_path", "kling_lip_sync.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 lip-sync 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)