calesthio/OpenMontage · error · KlingAPIError
Unexpected Kling Turbo task status {status!r}
Error message
Unexpected Kling Turbo task status {status!r} What it means
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.
Source
Thrown at tools/_kling/client.py:133
) -> list[dict[str, Any]]:
deadline = time.time() + timeout_seconds
while time.time() < deadline:
data = self.get("/tasks", params={"task_ids": task_id})
records = data.get("data") or []
if not records:
raise KlingAPIError(f"Kling Turbo poll response missing data[0]: {data}")
record = records[0]
status = record.get("status") or record.get("task_status")
if status == TURBO_SUCCESS_STATUS:
outputs = record.get("outputs") or []
if not isinstance(outputs, list):
raise KlingAPIError("Kling Turbo result path data[0].outputs is not a list")
return outputs
if status == TURBO_FAILURE_STATUS:
message = record.get("message") or record.get("error") or "Kling Turbo task failed"
raise KlingAPIError(str(message), code=record.get("code"), request_id=record.get("request_id"), response=data)
if status not in TURBO_PENDING_STATUSES:
raise KlingAPIError(f"Unexpected Kling Turbo task status {status!r}", response=data)
time.sleep(min(poll_interval, max(0.0, deadline - time.time())))
raise TimeoutError(f"Kling Turbo task {task_id} timed out after {timeout_seconds}s")
def _request(self, method: str, path: str, **kwargs: Any) -> dict[str, Any]:
url = self._url(path)
last_error: KlingAPIError | None = None
for attempt in range(self.max_retries + 1):
try:
response = getattr(self.session, method)(url, headers=self.headers, timeout=30, **kwargs)
self._raise_for_http_error(response)
data = response.json()
self._raise_for_business_error(data)
return data
except KlingAPIError as error:
last_error = error
if attempt >= self.max_retries or not is_retryable_kling_error(error):
raise
time.sleep(min(2.0 * (attempt + 1), 8.0))View on GitHub (pinned to 95e1c3d0ab)
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
Example fix
// schemas.py — before
TURBO_PENDING_STATUSES = {'pending', 'running'}
// schemas.py — after (extend once the new status is confirmed non-terminal)
TURBO_PENDING_STATUSES = {'pending', 'running', 'queued'} Defensive patterns
Strategy: try-catch
Validate before calling
from tools._kling.schemas import TURBO_PENDING_STATUSES, TURBO_SUCCESS_STATUS, TURBO_FAILURE_STATUS
def classify_turbo_status(record: dict) -> str:
s = record.get('status') or record.get('task_status')
if s == TURBO_SUCCESS_STATUS: return 'success'
if s == TURBO_FAILURE_STATUS: return 'failure'
if s in TURBO_PENDING_STATUSES: return 'pending'
return 'unknown' Type guard
def turbo_status_is_handled(status: str) -> bool:
from tools._kling.schemas import TURBO_PENDING_STATUSES, TURBO_SUCCESS_STATUS, TURBO_FAILURE_STATUS
return status in (TURBO_PENDING_STATUSES | {TURBO_SUCCESS_STATUS, TURBO_FAILURE_STATUS}) Try / catch
try:
outputs = client.poll_turbo(task_id)
except KlingAPIError as e:
if 'Unexpected Kling Turbo task status' in str(e):
logger.error('unknown turbo status, response: %s', e.response)
raise Prevention
- 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
When it happens
Trigger: 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.
Common situations: Turbo API version updates adding lifecycle states; tasks cancelled or expiring between polls; aggregator gateways translating statuses into non-standard strings.
Related errors
- Unexpected Kling Classic task status {status!r}
- Kling Turbo poll response missing data[0]: {data}
- Kling Turbo result path data[0].outputs is not a list
- Kling Turbo task {task_id} timed out after {timeout_seconds}
- Kling Classic task failed
AI-assisted analysis of calesthio/OpenMontage@95e1c3d0ab (2026-08-15).
Data as JSON: /api/errors/ee807657ea070cef.
Report an issue: GitHub.