# Errors

A refused request answers with an HTTP status and an error body. A task that fails after it was accepted reports error.code on the task and in its webhook.

## Error body

Every error response has the same shape. Branch on `error.code`, not on the message, which may change.

```json title="422 invalid_input"
{
  "error": {
    "code": "invalid_input",
    "message": "input does not match the model's schema",
    "retryable": false,
    "request_id": "9f2c41d07ab3e5c8a1d40be7c26f5e13",
    "errors": [
      { "path": "/settings/duration", "rule": "required" },
      { "path": "/settings/aspect_ratio", "rule": "value_not_allowed" }
    ]
  }
}
```

| Field | Meaning |
| --- | --- |
| `code` | Stable machine-readable reason. |
| `message` | A short description for logs. It never contains your input. |
| `retryable` | `true` only for 429 and 503: the same request may succeed later. |
| `request_id` | Include it when you contact support. |
| `errors` | On 422 input errors only: each failed field, as a JSON pointer into `input` (`path`) and a rule name (`rule`). |

## Request errors

These are the values of `error.code` on a refused request. The request created nothing and held no Credits.

| HTTP | `error.code` | Meaning | What to do |
| --- | --- | --- | --- |
| 400 | `invalid_input` | The request body is not valid JSON or does not have the request shape. | Fix the body. Do not retry unchanged. |
| 401 | `invalid_credentials` | The API key is missing, malformed, expired or revoked. | See [Authentication](/docs/authentication). |
| 402 | `insufficient_balance` | Available Credits cannot cover the hold. | Top up, then submit again. |
| 402 | `balance_negative` | The balance is below zero: a task's actual usage went past its hold and your balance, and Credits are owed. | Top up to bring the balance back to zero or above, then submit again. |
| 403 | `scope_denied` | The key lacks the scope for this operation or project. | Use a key with the scope. |
| 403 | `ip_not_allowed` | The request came from outside the key's IP allowlist. | Call from an allowed address. |
| 403 | `model_not_allowed` | The key's model allowlist excludes this model. | Allow the model on the key. |
| 403 | `budget_exceeded` | The key's daily or monthly spend limit would be exceeded. | Raise the limit or wait for the next UTC day or month. |
| 403 | `spending_blocked` | Spending is paused on the organization. | Contact support. |
| 404 | `resource_not_found` | The model, task or asset does not exist in this project. | Check the ID and the key's project. |
| 404 | `draft_not_found` | The `draft_task` names no succeeded draft of this project. | Use the ID of your own succeeded draft. |
| 409 | `conflict` | The request conflicts with the resource's state. | Read the resource, then decide. |
| 409 | `storage_quota_exceeded` | The organization's upload storage is full. | Delete assets you no longer need. |
| 422 | `invalid_input` | `input` does not match the model's schema, for example a media URL that is not `https`. `errors` lists each field. | Fix the fields named in `errors`. |
| 422 | `tier_not_sold` | The input is valid but selects a price tier your project cannot buy. | Change the resolution, the media or the length. |
| 422 | `input_media_invalid` | A media link's file has a format the model does not take in that field. | Send a supported format. See [Model inputs and media](/docs/media). |
| 422 | `input_media_too_large` | A media link's file is larger than the model allows for its kind. | Send a smaller file. See [Model inputs and media](/docs/media). |
| 422 | `input_duration_out_of_range` | A measured input video or audio is shorter or longer than the model or tier accepts, alone or in total. `errors` names each file or total with its rule (see below). A length the model's rules accept but the selected tier cannot price comes without `errors`; its message names the range the tier accepts. | Trim the media or pick another tier. |
| 422 | `draft_expired` | The draft is older than 7 days. | Generate a new draft. |
| 429 | `rate_limited` | A request rate or the open-task backlog is used up. | Wait `Retry-After` seconds. See [Rate limits](/docs/rate-limits). |
| 429 | `concurrency_limited` | As many tasks of this media type are running as your limit allows: by default 3 video tasks at once per organization (10 image, 10 audio). See [Rate limits](/docs/rate-limits). | Wait `Retry-After` seconds, or queue on your side. |
| 500 | `request_failed` | The request failed on our side. | For a create, check recent tasks before submitting again. |
| 503 | `temporarily_unavailable` | The service is briefly unavailable. | Retry later with backoff. |

Most creates are funded just after they are accepted. Then a balance, budget or spending refusal does not answer the request: the task is accepted with HTTP 202 and fails with the same code. See [Task errors](#task-errors).

The media checks read only the start of each linked file. When a check cannot read a file's format, size or duration, the request is still accepted and the model checks the file when it fetches it.

[Estimate a price](/docs/api/createEstimate) refuses the same input and media as a create, with the same errors. A create can still fail where an estimate succeeded: on balance or budget, on the rate and concurrency limits, or when a price changes in between.

> **Warning**
> A timeout or a dropped connection on a create is not an error body: the task may exist. Do not resend the create. Follow [Interrupted submissions](/docs/retries).

## Input field rules

A 422 lists one entry per failed field. Common `rule` values:

| `rule` | Meaning |
| --- | --- |
| `required` | A required field is missing. |
| `field_not_allowed` | The model's schema does not list this field. |
| `wrong_type` | The value has the wrong JSON type. |
| `value_not_allowed` | The value is not one of the allowed values here. |
| `out_of_range` | A number or length is outside its limits. |
| `bad_format` | A string does not have the required format, for example a media URL. |
| `too_many_items`, `too_few_items` | A list has too many or too few entries. |
| `prompt_or_contents` | Send exactly one of `prompt` and `contents` (Kling 4.0). |
| `frames_with_references` | Image frames cannot be combined with reference media. |
| `ratio_must_be_adaptive` | This kind of input only accepts `adaptive`. |
| `draft_not_upgradable` | Only a 480p draft can be turned into a final video. |
| `media_format`, `media_size` | With `input_media_invalid` or `input_media_too_large`: the linked file's format or size. |
| `video_length`, `media_length`, `video_total_too_long`, `audio_total_too_long`, `input_plus_output_too_long` | With `input_duration_out_of_range`: one file, or the files together, have a length the model does not accept. |

Each model has a reference page under **Models** in the docs navigation, with its fields, allowed values and rules.

## Task errors

A task accepted with HTTP 202 can still close without a result. Its `status` is `failed` or `canceled` and `error.code` names the reason. The webhook carries the same code as `error_code`, except `delivery_failed` and `generation_failed`, for which it may omit `error_code`. A task that closes without a result is not charged; its hold is released.

| `error.code` | Meaning | What to do |
| --- | --- | --- |
| `insufficient_balance` | Funding was refused: the balance could not cover the hold. | Top up, then submit a new task. |
| `balance_negative` | Credits were owed when the task came to be funded. | Top up to bring the balance back to zero or above, then submit a new task. |
| `budget_exceeded` | The key's daily or monthly spend limit would be exceeded. | Raise the limit or wait for the next UTC day or month. |
| `spending_blocked` | Spending is paused on the organization. | Contact support. |
| `recovery_review` | The task was waiting for funding when we restored service after an incident, and was closed for review. Nothing was held or charged. | Submit a new task. |
| `input_moderated` | Content safety refused the input. Moderation is always on; see [Content moderation](/docs/media#content-moderation). | Change the prompt or media. |
| `output_moderated` | Content safety refused the result. | Change the prompt or media. |
| `input_media_invalid` | The model refused a media file when it fetched it: its format, size or length, or its width, height, aspect ratio, pixel count or frame rate. | Check the model's media limits. |
| `input_media_unreachable` | The model could not fetch a media URL. | Keep the URL reachable until the task closes, or upload the file. |
| `input_rejected` | The model refused the input for another reason. | Change the input. |
| `draft_expired` | The draft expired before the final video started. | Generate a new draft. |
| `provider_unavailable` | The model was temporarily unavailable; the task was canceled. | Submit a new task later. |
| `delivery_failed` | The result was generated but could not be stored for download. | Submit a new task. |
| `generation_failed` | Any other failure. | Submit a new task; contact support if it repeats. |
