{"record":{"id":"ee807657ea070cef","repo":"calesthio/OpenMontage","slug":"unexpected-kling-turbo-task-status-status-r","errorCode":null,"errorMessage":"Unexpected Kling Turbo task status {status!r}","messagePattern":"Unexpected Kling Turbo task status (.+?)","errorType":"exception","errorClass":"KlingAPIError","httpStatus":null,"severity":"error","filePath":"tools/_kling/client.py","lineNumber":133,"sourceCode":"    ) -> list[dict[str, Any]]:\n        deadline = time.time() + timeout_seconds\n        while time.time() < deadline:\n            data = self.get(\"/tasks\", params={\"task_ids\": task_id})\n            records = data.get(\"data\") or []\n            if not records:\n                raise KlingAPIError(f\"Kling Turbo poll response missing data[0]: {data}\")\n            record = records[0]\n            status = record.get(\"status\") or record.get(\"task_status\")\n            if status == TURBO_SUCCESS_STATUS:\n                outputs = record.get(\"outputs\") or []\n                if not isinstance(outputs, list):\n                    raise KlingAPIError(\"Kling Turbo result path data[0].outputs is not a list\")\n                return outputs\n            if status == TURBO_FAILURE_STATUS:\n                message = record.get(\"message\") or record.get(\"error\") or \"Kling Turbo task failed\"\n                raise KlingAPIError(str(message), code=record.get(\"code\"), request_id=record.get(\"request_id\"), response=data)\n            if status not in TURBO_PENDING_STATUSES:\n                raise KlingAPIError(f\"Unexpected Kling Turbo task status {status!r}\", response=data)\n            time.sleep(min(poll_interval, max(0.0, deadline - time.time())))\n        raise TimeoutError(f\"Kling Turbo task {task_id} timed out after {timeout_seconds}s\")\n\n    def _request(self, method: str, path: str, **kwargs: Any) -> dict[str, Any]:\n        url = self._url(path)\n        last_error: KlingAPIError | None = None\n        for attempt in range(self.max_retries + 1):\n            try:\n                response = getattr(self.session, method)(url, headers=self.headers, timeout=30, **kwargs)\n                self._raise_for_http_error(response)\n                data = response.json()\n                self._raise_for_business_error(data)\n                return data\n            except KlingAPIError as error:\n                last_error = error\n                if attempt >= self.max_retries or not is_retryable_kling_error(error):\n                    raise\n                time.sleep(min(2.0 * (attempt + 1), 8.0))","sourceCodeStart":115,"sourceCodeEnd":151,"githubUrl":"https://github.com/calesthio/OpenMontage/blob/95e1c3d0ab93482159818560f6a8c8e866b9139f/tools/_kling/client.py#L115-L151","documentation":"Raised when poll_turbo() sees a status that is neither TURBO_SUCCESS_STATUS, TURBO_FAILURE_STATUS, nor in TURBO_PENDING_STATUSES. Like the Classic variant, this guards against unknown status enum values from schema drift or unusual task lifecycle states, and carries the full response payload on the exception.","triggerScenarios":"The Turbo gateway introduces a new status (e.g. 'cancelled', 'expired', 'partial'); the task was cancelled via the console; record.get('status') is empty while task_status holds a value outside the known sets.","commonSituations":"Turbo API version updates adding lifecycle states; tasks cancelled or expiring between polls; aggregator gateways translating statuses into non-standard strings.","solutions":["Log error.response to capture the exact status string and record shape","Compare against current Turbo API docs and update TURBO_PENDING_STATUSES or add terminal-state handling in schemas.py","If the status is terminal (cancelled/expired), surface it as a failure instead of polling forever"],"exampleFix":"// schemas.py — before\nTURBO_PENDING_STATUSES = {'pending', 'running'}\n\n// schemas.py — after (extend once the new status is confirmed non-terminal)\nTURBO_PENDING_STATUSES = {'pending', 'running', 'queued'}","handlingStrategy":"try-catch","validationCode":"from tools._kling.schemas import TURBO_PENDING_STATUSES, TURBO_SUCCESS_STATUS, TURBO_FAILURE_STATUS\n\ndef classify_turbo_status(record: dict) -> str:\n    s = record.get('status') or record.get('task_status')\n    if s == TURBO_SUCCESS_STATUS: return 'success'\n    if s == TURBO_FAILURE_STATUS: return 'failure'\n    if s in TURBO_PENDING_STATUSES: return 'pending'\n    return 'unknown'","typeGuard":"def turbo_status_is_handled(status: str) -> bool:\n    from tools._kling.schemas import TURBO_PENDING_STATUSES, TURBO_SUCCESS_STATUS, TURBO_FAILURE_STATUS\n    return status in (TURBO_PENDING_STATUSES | {TURBO_SUCCESS_STATUS, TURBO_FAILURE_STATUS})","tryCatchPattern":"try:\n    outputs = client.poll_turbo(task_id)\nexcept KlingAPIError as e:\n    if 'Unexpected Kling Turbo task status' in str(e):\n        logger.error('unknown turbo status, response: %s', e.response)\n    raise","preventionTips":["Watch Turbo API changelogs for new status enum values","Include cancelled/expired terminal states in your failure handling","Log the raw record for any status your code does not recognize"],"tags":["kling","api","turbo","polling","unknown-status","schema-drift"],"backgroundTag":null,"analyzedSha":"95e1c3d0ab93482159818560f6a8c8e866b9139f","analyzedAt":"2026-08-15T06:31:20.014Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}