Errors and retries
Every status and error code the Kling4 API returns, what each one means for your request, and how to retry without paying for the same video twice.
A failed call comes back with a non-2xx status and a JSON body in this shape:
{
"error": {
"code": "invalid_request",
"message": "Duration 40s exceeds maximum 30s",
"param": "duration",
"request_id": "req_7Hn2QeLx0pVb4sKd"
}
}Branch your code on code, which is stable. message is readable text you can log or show to users, and param names the field or header at fault when there is one. request_id, also sent in the X-Request-Id header, identifies the call; include it when you write to support.
One exception: the early per-IP throttles described in Authentication answer with 429, a Retry-After header and a flatter body, {"error": "too_many_requests", "message": "..."}, without a request_id.
Status and code reference
| Status | Codes | What happened | Retry? |
|---|---|---|---|
400 | invalid_request | The body is not valid JSON | No. Fix the body |
401 | invalid_api_key | The key is missing, malformed or revoked, or the account is suspended | No. Check the key |
402 | insufficient_credits, free_trial_exhausted | Available credits (balance minus credits on hold) do not cover the request, or a never-paid account used up its trial videos | Only after adding credits or once running tasks free up a hold |
403 | plan_upgrade_required, signup_credits_restricted | The plan does not include the model or resolution, or signup credits are on hold for review | No. Change the request or the plan, or contact support |
404 | task_not_found | No task with that ID exists on your account | No |
415 | invalid_request | Content-Type is not application/json | No. Fix the header |
422 | invalid_request, prompt_too_long, model_not_available, content_policy_violation | A field or media link failed validation, the prompt is too long or was blocked by moderation, or the model is switched off | No. Change the request |
429 | rate_limit_exceeded, concurrent_generation_limit_reached | The key hit its per-minute limit, or the account is already running as many videos as its plan allows | Yes, after a pause or once a task finishes |
500 | internal_error | Something failed on Kling4's side | Yes, with backoff (see the warning below for creates) |
502 | provider_error | Rendering could not be started | Yes, after a pause |
503 | service_unavailable and other codes | Generation or prompt moderation is offline for the moment | Yes, after a pause |
Treat the code list as open: handle unknown codes by their status. A 502 means the clip was never started and will not be charged, though the credits it held can take a little while to be released.
Retrying without duplicates
Reads are always safe to repeat, so retry GET /v1/tasks/{task_id} and GET /v1/credits freely. For 429, 500, 502 and 503, wait for Retry-After when it is sent, otherwise back off exponentially with random jitter, and stop after a fixed number of attempts.
A repeated create is a second video
POST /v1/videos/generations has no idempotency support, and an
Idempotency-Key header is ignored. If the first request did go through and
only the response was lost, a retry starts another video and holds credits for
it as well. Save every task_id you receive, and do not resend a create
automatically when a timeout leaves you unsure whether it succeeded.