{"record":{"id":"a1081cba336be8b7","repo":"calesthio/OpenMontage","slug":"kling-video-response-contained-no-downloadable-url-a1081c","errorCode":null,"errorMessage":"Kling video response contained no downloadable URL: {outputs}","messagePattern":"Kling video response contained no downloadable URL: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"tools/video/kling_official_video.py","lineNumber":704,"sourceCode":"            if inputs.get(key):\n                count += 1\n        return count\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 _first_output_url(outputs: list[dict[str, Any]]) -> str:\n        for item in outputs:\n            try:\n                return KlingOfficialVideo._output_url(item)\n            except ValueError:\n                continue\n        raise ValueError(f\"Kling video response contained no downloadable URL: {outputs}\")\n","sourceCodeStart":686,"sourceCodeEnd":705,"githubUrl":"https://github.com/calesthio/OpenMontage/blob/95e1c3d0ab93482159818560f6a8c8e866b9139f/tools/video/kling_official_video.py#L686-L705","documentation":"Raised by `_first_output_url(outputs)` after it iterated the entire outputs list and every item failed the `_output_url` extraction (which checks `url`, `video_url`, `resource_url`, then nested `resource.url`). It is the aggregate version of the per-item 'no downloadable URL' error: the whole list is embedded in the message so the developer can audit every response item at once.","triggerScenarios":"Same conditions as the per-item error, but affecting all outputs: a renamed URL field across the whole response, outputs being non-final status objects, or a provider payload shape change; also hit when `outputs` contains items whose `resource` is not a dict.","commonSituations":"API contract drift after a Kling version bump; polling loops feeding unfiltered task lists; moderation-flagged generations that return success-shaped items without assets. Distinct from the per-item error in that `_first_output_url` (used where only one URL is needed) tolerates individual bad items and only fails when none work.","solutions":["Dump the full `outputs` list from the error message and locate the real URL field name","Extend `_output_url` with the new field — fixing it once fixes both this and the per-item error","Ensure only completed, asset-bearing works are passed as outputs","If URLs were present but expired, regenerate: Kling remote URLs are time-limited"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"urls = [u for u in (extract_output_url(i) for i in outputs) if u]\nif not urls:\n    raise ValueError(f\"no downloadable URLs in outputs: {outputs}\")\nfirst = urls[0]","typeGuard":"def any_downloadable(outputs: list[dict]) -> bool:\n    return any(\n        i.get(\"url\") or i.get(\"video_url\") or i.get(\"resource_url\")\n        or (isinstance(i.get(\"resource\"), dict) and i[\"resource\"].get(\"url\"))\n        for i in outputs\n    )","tryCatchPattern":"try:\n    url = KlingOfficialVideo._first_output_url(outputs)\nexcept ValueError as e:\n    logger.error(\"response shape drift: %s\", e)\n    raise","preventionTips":["Snapshot real provider responses into test fixtures so URL-field renames fail in CI, not production","Pre-filter outputs to completed works before URL extraction"],"tags":["kling","video-generation","response-parsing","api-drift"],"backgroundTag":null,"analyzedSha":"95e1c3d0ab93482159818560f6a8c8e866b9139f","analyzedAt":"2026-08-15T06:31:20.014Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}