{"record":{"id":"e5cb2d522b538e94","repo":"calesthio/OpenMontage","slug":"kling-classic-result-path-data-task-result-result","errorCode":null,"errorMessage":"Kling Classic result path data.task_result.{result_key} is not a list","messagePattern":"Kling Classic result path data\\.task_result\\.(.+?) is not a list","errorType":"exception","errorClass":"KlingAPIError","httpStatus":null,"severity":"error","filePath":"tools/_kling/client.py","lineNumber":93,"sourceCode":"\n    def poll_classic(\n        self,\n        path: str,\n        task_id: str,\n        result_key: str,\n        timeout_seconds: int = 900,\n        poll_interval: float = 5.0,\n    ) -> list[dict[str, Any]]:\n        deadline = time.time() + timeout_seconds\n        while time.time() < deadline:\n            data = self.get(f\"{path.rstrip('/')}/{task_id}\")\n            payload = data.get(\"data\") or {}\n            status = payload.get(\"task_status\") or payload.get(\"status\")\n            if status == CLASSIC_SUCCESS_STATUS:\n                task_result = payload.get(\"task_result\") or {}\n                outputs = task_result.get(result_key) or []\n                if not isinstance(outputs, list):\n                    raise KlingAPIError(f\"Kling Classic result path data.task_result.{result_key} is not a list\")\n                return outputs\n            if status == CLASSIC_FAILURE_STATUS:\n                message = payload.get(\"task_status_msg\") or payload.get(\"message\") or \"Kling Classic task failed\"\n                raise KlingAPIError(str(message), code=payload.get(\"task_status\"), response=data)\n            if status not in CLASSIC_PENDING_STATUSES:\n                raise KlingAPIError(f\"Unexpected Kling Classic task status {status!r}\", response=data)\n            time.sleep(min(poll_interval, max(0.0, deadline - time.time())))\n        raise TimeoutError(f\"Kling Classic task {task_id} timed out after {timeout_seconds}s\")\n\n    def create_turbo(self, path: str, payload: dict[str, Any]) -> str:\n        data = self.post(path, payload)\n        task_id = ((data.get(\"data\") or {}).get(\"id\"))\n        if not task_id:\n            raise KlingAPIError(f\"Kling Turbo create response missing data.id: {data}\")\n        return str(task_id)\n\n    def poll_turbo(\n        self,","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/calesthio/OpenMontage/blob/95e1c3d0ab93482159818560f6a8c8e866b9139f/tools/_kling/client.py#L75-L111","documentation":"KlingAPIError raised inside poll_classic when the task reached the success status but data.task_result.<result_key> is present yet not a list. The poller's contract is to return a list of output records (usually one element with a URL); a dict, string, or null in that position violates the contract, so it refuses to return a malformed result rather than crash later on iteration.","triggerScenarios":"Polling a completed classic task where result_key doesn't match this endpoint's actual result field — e.g. asking for 'task_result.images' when the route returns a single object under a different key — so .get(result_key) yields something non-list; also schema changes on Kling's side after success.","commonSituations":"Calling poll_classic with the result_key copied from a different endpoint's example; API revision changing an endpoint from list-shaped to object-shaped results; task_result partially populated for multi-output tasks.","solutions":["Inspect the raw payload: temporarily log the full data at success status and find the actual key/shape under data.task_result","Correct the result_key argument to the endpoint's documented result field for that route","If the field legitimately became a single object, wrap it client-side: outputs = [obj] if isinstance(obj, dict) else obj","Pin to a known-good provider API version / check the changelog if Kling shipped a breaking change"],"exampleFix":"# before\noutputs = client.poll_classic(path, task_id, result_key=\"videos\")  # dict comes back\n\n# after\noutputs = client.poll_classic(path, task_id, result_key=\"task_result\")\nif isinstance(outputs, dict):\n    outputs = [outputs]","handlingStrategy":"type-guard","validationCode":"# verify result_key against the raw success payload once, then poll\nsample = client.get(f\"{path.rstrip('/')}/{task_id}\")\nresult = ((sample.get(\"data\") or {}).get(\"task_result\") or {}).get(result_key)\nif result is not None and not isinstance(result, list):\n    raise SystemExit(f\"result_key {result_key!r} is {type(result).__name__}, not list — wrong key for this endpoint?\")","typeGuard":"def is_output_list(value) -> bool:\n    return isinstance(value, list)","tryCatchPattern":"try:\n    outputs = client.poll_classic(path, task_id, result_key)\nexcept KlingAPIError as e:\n    if \"is not a list\" in str(e):\n        raise SystemExit(f\"result shape mismatch for key {result_key!r} — inspect data.task_result in the raw response\")\n    raise","preventionTips":["Use the result_key documented for the exact endpoint, not one copied from another route's example","Log the raw success payload once per endpoint integration to lock the schema","Wrap single-object results into a list at the call boundary if an endpoint is object-shaped"],"tags":["kling","api-schema","polling","type-mismatch"],"backgroundTag":null,"analyzedSha":"95e1c3d0ab93482159818560f6a8c8e866b9139f","analyzedAt":"2026-08-15T06:31:20.014Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}