{"record":{"id":"470e9dcbabbe5fae","repo":"calesthio/OpenMontage","slug":"kling-image-response-item-contained-no-downloadabl","errorCode":null,"errorMessage":"Kling image response item contained no downloadable URL: {item}","messagePattern":"Kling image response item contained no downloadable URL: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"tools/graphics/kling_official_image.py","lineNumber":390,"sourceCode":"        base_path = Path(inputs.get(\"output_path\", \"kling_official_image.png\"))\n        paths: list[Path] = []\n        for index, item in enumerate(outputs):\n            url = self._output_url(item)\n            suffix = extension_from_url(url, \".png\")\n            output_path = numbered_output_path(output_path_with_suffix(base_path, suffix), index, suffix)\n            client.download(url, output_path)\n            paths.append(output_path)\n        return paths\n\n    @staticmethod\n    def _output_url(item: dict[str, Any]) -> str:\n        url = item.get(\"url\") or item.get(\"image_url\") or item.get(\"resource_url\")\n        if url:\n            return str(url)\n        resource = item.get(\"resource\") or {}\n        if isinstance(resource, dict) and resource.get(\"url\"):\n            return str(resource[\"url\"])\n        raise ValueError(f\"Kling image response item contained no downloadable URL: {item}\")\n\n    @staticmethod\n    def _prompt(inputs: dict[str, Any]) -> str:\n        prompt = str(inputs.get(\"prompt\") or \"\").strip()\n        if not prompt:\n            raise ValueError(\"prompt is required\")\n        return prompt\n\n    @staticmethod\n    def _copy_common_task_fields(inputs: dict[str, Any], payload: dict[str, Any]) -> None:\n        if \"watermark\" in inputs:\n            payload[\"watermark_info\"] = {\"enabled\": bool(inputs.get(\"watermark\"))}\n        callback_url = validate_callback_url(inputs.get(\"callback_url\"))\n        if callback_url:\n            payload[\"callback_url\"] = callback_url\n        if inputs.get(\"external_task_id\"):\n            payload[\"external_task_id\"] = inputs[\"external_task_id\"]\n","sourceCodeStart":372,"sourceCodeEnd":408,"githubUrl":"https://github.com/calesthio/OpenMontage/blob/95e1c3d0ab93482159818560f6a8c8e866b9139f/tools/graphics/kling_official_image.py#L372-L408","documentation":"Raised by KlingOfficialImage._output_url when a completed Kling image task returns a results item that contains none of the URL fields the tool knows how to download ('url', 'image_url', 'resource_url', or a nested 'resource.url'). It means the task reached a terminal state but the response shape does not match any expected layout, so there is nothing to fetch and write to disk. This is almost always an API-side schema change or an unusual response variant rather than a caller mistake.","triggerScenarios":"Calling kling_official_image with a prompt that succeeds at task level; the polled task detail returns items in results whose entries only carry, e.g., a base64 field or a differently-named key. Also triggered if the API starts wrapping URLs one level deeper than 'resource'.","commonSituations":"Kling ships a new model variant whose response payload differs; a proxy/gateway rewrites the response; the tool's supported field list falls behind the live API version.","solutions":["Print/inspect the full item dict from the exception message to see which field actually carries the URL","Add the observed key to the _output_url candidate chain (url/image_url/resource_url/resource.url)","Check the Kling API changelog for the model used and update the tool","If items contain base64 data instead of URLs, decode and write directly instead of downloading"],"exampleFix":"// before\nurl = item.get(\"url\") or item.get(\"image_url\") or item.get(\"resource_url\")\n// after\nurl = (\n    item.get(\"url\")\n    or item.get(\"image_url\")\n    or item.get(\"resource_url\")\n    or (item.get(\"resource\") or {}).get(\"url\")\n    or item.get(\"download_url\")  # newly observed field\n)","handlingStrategy":"try-catch","validationCode":"def has_downloadable_url(item: dict) -> bool:\n    if item.get(\"url\") or item.get(\"image_url\") or item.get(\"resource_url\"):\n        return True\n    res = item.get(\"resource\")\n    return isinstance(res, dict) and bool(res.get(\"url\"))","typeGuard":"def is_kling_result_item(item: Any) -> bool:\n    return isinstance(item, dict) and bool(\n        item.get(\"url\") or item.get(\"image_url\")\n        or item.get(\"resource_url\")\n        or (isinstance(item.get(\"resource\"), dict) and item[\"resource\"].get(\"url\"))\n    )","tryCatchPattern":"try:\n    paths = tool.run(inputs)\nexcept ValueError as e:\n    if \"no downloadable URL\" in str(e):\n        logger.error(\"Kling response schema drift; item=%s\", e)\n        # surface item payload for schema fix; do not retry unchanged\n    raise","preventionTips":["Pin to tested Kling API/model versions","Log full response items in debug mode so schema drift is diagnosable","Wrap provider calls with a response-shape assertion layer that alerts on drift"],"tags":["kling","image-generation","api-schema","response-parsing"],"backgroundTag":null,"analyzedSha":"95e1c3d0ab93482159818560f6a8c8e866b9139f","analyzedAt":"2026-08-15T06:31:20.014Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}