> ## Documentation Index
> Fetch the complete documentation index at: https://docs.youka.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Ошибки

> Обработка YoukaRequestError, YoukaTaskError и повторяемых сбоев

SDK предоставляет два класса ошибок: `YoukaRequestError` для HTTP-ошибок и ошибок валидации, и `YoukaTaskError` для асинхронных задач, завершившихся в состоянии, отличном от успешного. Оба расширяют `Error` и содержат структурированные поля, чтобы вы могли ветвить логику по коду, статусу и возможности повтора.

## `YoukaRequestError`

Выбрасывается при HTTP-ошибках, ошибках валидации запроса и некорректных ответах.

```ts theme={null}
import { YoukaRequestError } from "@youka/sdk";

try {
  await client.projects.create(body);
} catch (error) {
  if (error instanceof YoukaRequestError) {
    console.error({
      code: error.code,
      message: error.message,
      status: error.status,
      retryable: error.retryable,
      details: error.details,
    });
  } else {
    throw error;
  }
}
```

### Поля

<ParamField path="code" type="string">
  Машиночитаемый код ошибки, например `INVALID_REQUEST`, `UNAUTHORIZED`,
  `UPLOAD_FAILED`.
</ParamField>

<ParamField path="message" type="string">
  Человекочитаемое описание.
</ParamField>

<ParamField path="status" type="number">
  HTTP-код статуса, если доступен.
</ParamField>

<ParamField path="retryable" type="boolean">
  `true`, если SDK считает, что ошибку имеет смысл повторить (лимиты запросов,
  временные ошибки сервера, идемпотентное повторение в процессе).
</ParamField>

<ParamField path="details" type="unknown">
  Детали от сервера; обычно список проблем Zod для ошибок валидации.
</ParamField>

### Частые коды

| Код                             | Причина                                                                         | Повторяемо?       |
| ------------------------------- | ------------------------------------------------------------------------------- | ----------------- |
| `INVALID_REQUEST`               | Тело запроса не прошло проверку схемы до отправки.                              | No                |
| `UNAUTHORIZED`                  | Отсутствует или неверный API key.                                               | No                |
| `NOT_FOUND`                     | Ресурс не существует или у вас нет доступа.                                     | No                |
| `CONFLICT`                      | Конфликт версий (HTTP 409).                                                     | Yes               |
| `TOO_MANY_REQUESTS`             | Превышен лимит запросов (HTTP 429).                                             | Yes               |
| `INTERNAL_SERVER_ERROR`         | Временный сбой сервера (HTTP 500).                                              | Yes               |
| `IDEMPOTENT_REPLAY_IN_PROGRESS` | Исходный запрос всё ещё выполняется с тем же ключом идемпотентности (HTTP 202). | Yes               |
| `INVALID_RESPONSE`              | Сервер вернул тело, не соответствующее ожидаемой схеме.                         | No                |
| `UPLOAD_FAILED`                 | Загрузка по подписанному URL вернула не-2xx.                                    | Зависит от status |

## `YoukaTaskError`

Выбрасывается из `client.tasks.wait(...)`, `client.projects.wait(...)` и `client.exports.wait(...)`, когда базовая задача или экспорт завершается в `failed`, `cancelled` или `timed-out`.

```ts theme={null}
import { YoukaTaskError } from "@youka/sdk";

try {
  await client.projects.wait(created);
} catch (error) {
  if (error instanceof YoukaTaskError) {
    console.error({
      code: error.code,
      message: error.message,
      status: error.status,
      task: error.task,
    });
  } else {
    throw error;
  }
}
```

### Поля

<ParamField path="code" type="'TASK_FAILED' | 'TASK_CANCELLED' | 'TASK_TIMED_OUT'">
  Напрямую соответствует конечному статусу задачи.
</ParamField>

<ParamField path="message" type="string">
  Либо сообщение об ошибке задачи, предоставленное сервером, либо сгенерированное резервное.
</ParamField>

<ParamField path="status" type="TaskStatus">
  Конечный статус задачи.
</ParamField>

<ParamField path="task" type="RestTask">
  Полная полезная нагрузка задачи на момент сбоя. Полезно для логирования и
  пользовательских сообщений об ошибках.
</ParamField>

## Шаблон повторов

Комбинируйте `retryable` с ключом идемпотентности, чтобы построить безопасный цикл повторов:

```ts theme={null}
import { YoukaRequestError } from "@youka/sdk";

async function createWithRetry<T>(fn: () => Promise<T>, maxAttempts = 3) {
  let lastError: unknown;

  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      return await fn();
    } catch (error) {
      lastError = error;
      if (
        error instanceof YoukaRequestError &&
        error.retryable &&
        attempt < maxAttempts
      ) {
        await new Promise((r) => setTimeout(r, 2 ** attempt * 1_000));
        continue;
      }
      throw error;
    }
  }

  throw lastError;
}

await createWithRetry(() =>
  client.projects.create(body, {
    idempotencyKey: "import-2026-04-08-song-001",
  }),
);
```

<Tip>
  Всегда повторно используйте один и тот же ключ идемпотентности между попытками. Иначе сервер
  воспринимает повтор как новый запрос, и у вас могут появиться дубликаты.
</Tip>

## Прерывание и отмена

Прерывание запроса выбрасывает стандартный `AbortError`, а не `YoukaRequestError`. Проверяйте его явно:

```ts theme={null}
try {
  await client.projects.wait(created, { signal: controller.signal });
} catch (error) {
  if (error instanceof Error && error.name === "AbortError") {
    console.log("Cancelled by user");
    return;
  }
  throw error;
}
```

## Что дальше

* [Tasks](/ru/sdk/tasks) — хелперы ожидания и продвинутое опрашивание задач
* [Authentication](/ru/sdk/authentication) — параметры конструктора и сигналы
* [API errors](/ru/api/errors) — те же коды в «сыром» HTTP
