# Ошибки

Любая ошибка — HTTP-статус и один конверт (схема `Error`). Ветвитесь по `error.type` и
`error.code`; `message` подсказывает, что делать, но его формулировка может меняться.

<!-- openapi: #/components/schemas/Error -->
```json
{
  "error": {
    "type": "invalid_request_error",
    "code": "capability_mismatch",
    "message": "the model does not support this value",
    "detail": [{"path": "aspect_ratio", "reason": "unsupported_value", "allowed": ["1:1", "16:9", "9:16"]}]
  }
}
```

## Тип — что делать программе

| `type` | Статусы | Что делать |
|---|---|---|
| `invalid_request_error` | 400, 405, 413, 415 | исправить запрос по `detail[]`; `405` — у адреса нет такого метода (`Allow`); `415` — тело не `application/json` (у загрузки файла и транскрибации — не `multipart/form-data`) |
| `authentication_error` | 401 | проверить ключ |
| `billing_error` | 402 | пополнить баланс или поднять лимит; повтор не поможет |
| `permission_error` | 403 | не тот вид ключа, действие только в кабинете, роли не хватает (причина — в `detail[].reason`), не сошлась подпись ссылки на файл или аккаунт либо ключ заблокирован службой поддержки (`account_blocked`, `key_blocked` — повтор не поможет, напишите в поддержку) |
| `not_found_error` | 404, 410 | нет такой модели, задачи, файла или адреса; `410` — срок файла вышел |
| `conflict_error` | 409 | тот же `Idempotency-Key` с другим запросом |
| `rate_limit_error` | 429 | подождать `Retry-After` и повторить |
| `model_error` | 502, 503, 504 | модель не справилась (`502 generation_failed`), неизвестная ошибка (`502 unknown_error`), её сейчас некому выполнить (`503 model_unavailable`, с `Retry-After`) или ответа не дождались (`504`: запрос мог выполниться — повтор с тем же `Idempotency-Key` вернёт задачу), сервер занят большими запросами (`503 overloaded`, с `Retry-After`), идут плановые работы (`503 maintenance`, срок — в `ends_at`) — повторить позже |
| `server_error` | 500 | наша ошибка; повторить, при повторении — написать нам |

## Код — что случилось

`code` — закрытый словарь (схема `ErrorCode`): `invalid_request`, `invalid_input` (файл или
значение отвергнуты), `capability_mismatch` (модель не принимает поле или значение),
`content_policy`, `invalid_api_key`, `account_blocked` (аккаунт заблокирован службой поддержки:
новые запросы не принимаются, чтение задач и результатов работает), `key_blocked` (ключ
заблокирован службой поддержки), `insufficient_balance`, `key_spend_limit_exceeded`,
`member_spend_limit_exceeded`, `invalid_signature`, `unauthorized` (сессия кабинета
недействительна), `forbidden` (не тот вид ключа или не хватает роли), `not_found` (нет
такого адреса), `model_not_found`, `job_not_found`, `file_not_found`, `file_expired`,
`idempotency_key_conflict`, `secret_unavailable` (секрет ключа показать нельзя — создайте
новый), `rate_limited`, `generation_failed`, `unknown_error` (неизвестная ошибка), `model_unavailable`, `no_channel_matches`
(`routing_options` отсекли все каналы), `storage_limit_exceeded` (загрузки `POST /v1/files`
заняли квоту), `overloaded` (сервер занят большими запросами),
`maintenance` (плановые работы), `internal_error`.

## Деталь — что поправить

`detail[]` — когда известно, что именно не так: `path` — поле запроса так, как вы его
прислали (`aspect_ratio`, `references[1]`, `elements[0].images[1]`), `reason` — причина из
словаря (схема `DetailReason`: `required`, `unsupported_field`, `unsupported_value`,
`incompatible_value`, `out_of_range`, `too_long`, `too_many_items` (файлов или элементов
больше, чем принимает модель, — в `allowed` предел), `unsupported_format`, `too_large`…),
`allowed` — что было бы принято.

- Поле, которого у ручки нет, — `400 invalid_request` с
  `{"path": "<поле>", "reason": "unsupported_field"}`. Значение, которое у модели ничего не
  меняет, **принимается молча**: её умолчание, `auto`, поле, которого у модели
  нет, с тем значением, которое она и так даёт ([Запросы и ответы](https://souz.ai/docs/conventions.md)).
- `no_channel_matches` — `routing_options` отсекли все каналы модели; `detail[].reason` —
  `not_selected`, `above_max_price` или `fallback_disabled` ([Каналы](https://souz.ai/docs/channels.md#ошибки-выбора)).
- Модель другой модальности — `400 invalid_request` с подсказкой пути:
  `{"path": "model", "reason": "wrong_endpoint", "allowed": ["/v1/videos"]}`.
- Причина, которую назвала сама модель после приёма, приходит той же формой в `error`
  проваленной задачи (у контентного фильтра — `content_policy_category`). Чаще её нет —
  тогда только `code` и `message`.

## Ошибки задачи

| `code` | Статус | Что случилось | Что делать |
|---|---|---|---|
| `invalid_input` | 400 | модель отвергла входные данные: параметр, файл, формат, размер или длительность | исправить по `detail[]`, без него — сверить запрос со схемой модели (`GET /v1/models/{id}`); повтор того же запроса не поможет |
| `content_policy` | 400 | сработал контентный фильтр: после отказа фильтра запрос пробует ещё один канал по пресету, и тот тоже отказал или не вернул результата | переписать описание или заменить файлы; деньги не списаны |
| `generation_failed` | 502 | модель приняла запрос и не справилась: ответила без результата, задача у канала завершилась неудачей | повторить; деньги не списаны |
| `unknown_error` | 502 | неизвестная ошибка: ответ, который мы не смогли разобрать, или сбой на нашей стороне; подробностей нет | повторить; деньги не списаны; мы разбираем такие случаи |
| `model_unavailable` | 503 | каналы модели сейчас недоступны: на паузе, перегружены, упёрлись в лимит, не ответили вовремя или подходящих каналов нет | повторить позже или выбрать другую модель |

`unknown_error` появился 08.10.2026: часть отказов, которые раньше приходили как
`503 model_unavailable` (сбой на нашей стороне, ответ, который мы не разобрали), теперь
приходит как `502 unknown_error`. Если программа повторяет запрос по коду
`model_unavailable`, повторяйте и `unknown_error`.

Если каналы отказали по-разному, код — по главной причине: отказ контентного фильтра или
окончательный отказ входных данных важнее последующих сбоев других каналов. После отказа
фильтра и сбоя соседнего канала придёт `content_policy`, а не `generation_failed`.

## Плановые работы — `503 maintenance`

На время плановых работ новые запросы (`POST`, `PUT`, `PATCH`, `DELETE`) получают `503` с
`code: "maintenance"`, заголовком `Retry-After` и сроком в конверте: `ends_at` — до какого
времени работы, `reason` — что делаем.

<!-- openapi: #/components/schemas/Error -->
```json
{
  "error": {
    "type": "model_error",
    "code": "maintenance",
    "message": "scheduled maintenance: new requests are paused until ends_at; retry after it, accepted jobs finish afterwards and nothing needs to change on your side",
    "reason": "Обновление сервиса",
    "ends_at": "2026-10-04T14:15:00+03:00"
  }
}
```

- Повторите запрос после `ends_at`; `Retry-After` — через сколько секунд спросить снова,
  если работы закончатся раньше. Переключаться никуда не нужно: принятые до работ задачи
  доделываются после них, за непринятый запрос деньги не списываются.
- Чтение работает и во время работ: задачи, их события, файлы, каталог, `GET /v1/key`. Если
  на время работ остановлен весь сервис, `503 maintenance` приходит и на чтение — с тем же
  сроком.
- Состояние — `GET /v1/status` без ключа, отвечает и при остановленном сервисе:
  `{"status": "ok"}`, во время работ —
  `{"status": "maintenance", "reason": "…", "started_at": "…", "ends_at": "…"}` (схема
  `ServiceStatus`). `503 {"status": "unavailable"}` — сбой вне плановых работ: повторите
  позже.

---

Оглавление документации: https://souz.ai/llms.txt. Всё руководство одним файлом: https://souz.ai/llms-full.txt. Справочник методов: https://souz.ai/docs/api-reference.md.
