Ошибки API Jev: 401, 422, 429, 529 — причины и решения

Обновлено

API Jev возвращает четыре основных кода ошибок. Два из них лечатся исправлением запроса, ещё два — повтором с задержкой. Разбираем, что означает каждый код, какие исключения бросают SDK TypeSafe и чем отличаются ответы Polza.AI, Vercel и Cloudflare.

Коротко: четыре кода

Код Что случилось Повторять? Что делать
401 Unauthorized Ключа нет или он неверный Нет Проверить заголовок Authorization, ключ и адрес площадки
422 Unprocessable Entity Тело запроса не прошло проверку Нет Исправить поле, указанное в ответе
429 Too Many Requests Превышен лимит запросов или токенов Да, с задержкой Экспоненциальная пауза, заголовок Retry-After, меньше параллельных запросов
529 Overloaded TypeSafe временно перегружен Да, с задержкой Экспоненциальная пауза, SDK справится сам

Ошибки приходят со стандартным HTTP-кодом и JSON-телом. По документации Vercel и Polza.AI, в теле ошибки TypeSafe есть текст message и машиночитаемый тип error_type. Пример из документации Vercel:

{
  "message": "questions.refund.type: expected one of 'noul', 'choice', 'score'",
  "error_type": "invalid_request"
}

В ответах API есть заголовок x-typesafe-request-id с идентификатором запроса. Сохраняйте его в логах: по нему поддержка найдёт конкретный вызов.

401: ключ не принят

Частые причины:

  • нет заголовка Authorization: Bearer <ключ> или в нём опечатка;
  • ключ от другой площадки: например, ключ Polza.AI отправлен на api.typesafe.ai или ключ TypeSafe — в OpenRouter;
  • ключ отозван. Ключи TypeSafe управляются в консоли console.typesafe.ai;
  • в Vercel истёк локальный OIDC-токен: он живёт 12 часов, обновите его командой vercel env pull;
  • в Cloudflare у токена нет права Workers AI. Такой токен получает 401 с кодом ошибки 10000.

Python SDK проверяет ключ ещё при создании клиента. Пробелы и переводы строк по краям он обрезает, а пустой ключ, пробелы внутри, управляющие и не-ASCII символы отклоняет с TypeSafeError до отправки запроса. Так ловится, например, кириллическая буква, попавшая в ключ при копировании. Явно переданный пустой ключ не заменяется значением из TYPESAFE_API_KEY.

Быстро проверить ключ можно запросом списка моделей:

curl -i https://api.typesafe.ai/v1/models \
  -H "Authorization: Bearer $TYPESAFE_API_KEY"

Если здесь ответ 200, ключ рабочий: проверьте адрес и заголовок в основном запросе. При 401 от сервера Python SDK бросает TypeSafeAuthenticationError, JavaScript SDK — AuthenticationError. Повторять такой запрос бессмысленно.

422: запрос не прошёл валидацию

Сервер отвечает 422, когда тело запроса не проходит проверку: например, не хватает обязательного поля или вопрос описан неверно. В теле ответа указано поле с ошибкой. Проверьте по списку:

  • есть все три обязательных поля: model, state, questions;
  • у каждого вопроса есть type (noul, choice или score) и instructions;
  • у choice поле criteria — объект «вариант: описание», вариантов не больше 255, описание может быть null;
  • у score поле criteria — упорядоченный массив минимум из двух и максимум из десяти уровней;
  • у noul поле criteria необязательно, а в нём допустимы только ключи true и false.

Обратите внимание на две ловушки. Первая — тип boolean вместо noul. Так вопрос «да/нет» называется в эндпоинте оценки Vercel, и при переносе кода между форматами его легко перепутать: пример ошибки выше как раз про это. Вторая — criteria у score в виде объекта с числовыми ключами. Этот формат убрали в SDK версии 0.6.0: теперь уровни передаются упорядоченным списком.

Часть проверок Python SDK делает локально: пустой словарь вопросов или пустой список уровней у score даст TypeSafeError без запроса к серверу. Ответ 422 от сервера превращается в TypeSafeUnprocessableEntityError, в JavaScript — в UnprocessableEntityError. Повтор не поможет, нужно исправить запрос.

Отдельно следите за размером. Лимит модели — 64 000 токенов на весь запрос и 32 000 на state вместе с самым длинным вопросом. Какой код вернёт TypeSafe при превышении, документация не уточняет. Polza.AI в этом случае отвечает 400.

429: превышен лимит

По документации TypeSafe, у Jev 1.13 два лимита: 1200 запросов в минуту и 250 000 токенов в секунду. Превышение любого из них даёт 429. Компания предупреждает, что лимиты сейчас меняются динамически и без уведомления: спрос большой, мощности добавляются. Повышенные лимиты доступны на индивидуальных и корпоративных тарифах.

Что делать:

  • Ждать, а не повторять сразу. Если в ответе есть заголовок Retry-After или retry-after-ms, подождите указанное время. SDK достают его сами: в Python поле retry_after_ms у TypeSafeRateLimitError, в JavaScript — retryAfterMs у RateLimitError.
  • Ограничить параллельность. Как это сделать в асинхронном коде, показано в статье об асинхронном клиенте на Python.
  • Объединять вопросы. Десять вопросов к одному тексту лучше задать одним запросом, а не десятью. Запросов станет меньше, а текст будет оплачен один раз. Подробнее в статье о fan-out запросах.

У площадок-посредников лимиты свои. Например, на бесплатном тарифе Vercel AI Gateway лимиты на модель ниже, чем на платном.

529: TypeSafe перегружен

Код 529 не входит в стандартный набор HTTP, TypeSafe использует его для временной перегрузки. Ваш запрос корректен, повторите его с экспоненциальной задержкой. Python SDK относит 529 к TypeSafeInternalServerError (все ответы 5xx), JavaScript SDK — к InternalServerError. Оба SDK по умолчанию повторяют ответы 500–599, поэтому при короткой перегрузке запрос будет повторён без вашего участия.

Если 529 приходит постоянно и повторы не помогают, это сбой на стороне сервиса. Для важных сценариев держите запасной путь: другую площадку с Jev или отложенную обработку очереди.

Как SDK повторяют запросы

Настройки повторов в двух SDK совпадают по смыслу, различаются только имена:

Что Python (RetryPolicy) JavaScript (RetryPolicy) По умолчанию
Число повторов max_retries maxRetries 2
Первая пауза backoff_initial backoffInitialMs 0,5 с, удваивается
Максимальная пауза backoff_max backoffMaxMs 5 с
Случайное уменьшение паузы backoff_jitter backoffJitter до 25%
Какие коды повторять http_statuses httpStatuses 408, 429, 500–599
Учитывать Retry-After respect_retry_after respectRetryAfter да

Обрывы соединения и таймауты оба SDK тоже повторяют по умолчанию. В Python у RetryPolicy есть общий бюджет времени на вызов, timeout: 30 секунд вместе с паузами. Если следующая пауза не укладывается в бюджет, SDK прекращает попытки и бросает последнюю ошибку. В JavaScript таймаут задаётся на попытку (10 секунд), а ожидание по Retry-After ограничено параметром maxRetryAfterMs (60 секунд).

Обработка ошибок в Python после всех повторов:

from typesafe_sdk import (
    Noul,
    RetryPolicy,
    TypeSafeAPIConnectionError,
    TypeSafeAuthenticationError,
    TypeSafeClient,
    TypeSafeInternalServerError,
    TypeSafeRateLimitError,
    TypeSafeUnprocessableEntityError,
)

client = TypeSafeClient(retry=RetryPolicy(max_retries=4, backoff_max=10.0, timeout=60.0))

try:
    result = client.system_one(
        "Верните деньги за двойное списание!",
        {"refund": Noul(instructions="Клиент просит вернуть деньги?")},
    )
except TypeSafeAuthenticationError:
    raise  # 401: проверьте ключ и адрес площадки
except TypeSafeUnprocessableEntityError as error:
    print("Ошибка в запросе:", error.body)  # 422
except TypeSafeRateLimitError as error:
    print("Лимит:", error.retry_after_ms, error.request_id)  # 429 после всех повторов
except TypeSafeInternalServerError as error:
    print("Сбой сервиса:", error.status, error.request_id)  # 5xx, включая 529
except TypeSafeAPIConnectionError:
    print("Нет соединения или истёк таймаут")

Все HTTP-ошибки наследуются от TypeSafeAPIError: у них есть status, body, headers и request_id. Таймаут (TypeSafeAPITimeoutError) — частный случай ошибки соединения. Подробнее о клиенте — в статье о Python SDK.

Без SDK: повтор вручную

Если вы вызываете API напрямую, повторяйте запрос сами. Минимальный вариант на Python с библиотекой requests:

import os
import random
import time

import requests

URL = "https://api.typesafe.ai/v1/systemone"
RETRYABLE = {408, 429} | set(range(500, 600))


def system_one(payload: dict, max_retries: int = 4) -> dict:
    headers = {"Authorization": f"Bearer {os.environ['TYPESAFE_API_KEY']}"}
    for attempt in range(max_retries + 1):
        response = requests.post(URL, json=payload, headers=headers, timeout=10)
        if response.status_code not in RETRYABLE or attempt == max_retries:
            response.raise_for_status()  # 401 и 422 не повторяем
            return response.json()
        try:
            delay = float(response.headers["Retry-After"])
        except (KeyError, ValueError):
            delay = min(0.5 * 2**attempt, 5.0) * random.uniform(0.75, 1.0)
        time.sleep(delay)

Ошибки шлюзов и агрегаторов

Площадки-посредники добавляют свои коды:

Площадка Особенности
Polza.AI Ошибки валидации приходят как 400 вместо 422. Нехватка денег на балансе — 402 (insufficient_balance), недоступность или перегрузка провайдера — 503. Формат ошибки: error.code, error.message, trace_id, а форма TypeSafe дублируется в поле detail
Vercel AI Gateway Ошибки провайдера передаются без изменений. Свои коды шлюза: 401 (ключ или OIDC-токен), 402 (нет кредитов или исчерпан бюджет), 403 (модель вне бесплатного набора, не добавлен способ оплаты или сработало ограничение команды)
Cloudflare Токен без права Workers AI получает 401 с кодом 10000

SDK TypeSafe повторяют и 503, так как он попадает в диапазон 500–599. А вот 402 не повторяется: пополните баланс. Как устроены ошибки у российского агрегатора, подробно описано в статье о подключении через Polza.AI.

Что приложить к обращению в поддержку

  • идентификатор запроса: заголовок x-typesafe-request-id или поле request_id у исключения, а для Polza.AI — trace_id;
  • код ответа, тело ошибки и время запроса;
  • лог с подробностями. Уровень debug включается переменной TYPESAFE_LOG_LEVEL=debug до импорта SDK: он запишет заголовки и тела запросов и ответов. Секретные заголовки SDK скрывает, а тела нет, поэтому проверьте лог на персональные данные перед отправкой.

Полный формат запроса и ответа собран в справочнике API Jev.

Частые вопросы

Что значит ошибка 529 в API Jev?

Сервис TypeSafe временно перегружен. Сам запрос корректен, его нужно повторить с экспоненциальной задержкой. Официальные SDK делают это автоматически.

Почему Jev возвращает 422?

Тело запроса не прошло проверку: нет обязательного поля, неверный type вопроса, у choice больше 255 вариантов или у score меньше двух или больше десяти уровней. В теле ответа указано поле с ошибкой.

Сколько запросов в минуту можно отправлять в Jev?

По документации TypeSafe — до 1200 запросов в минуту и до 250 000 токенов в секунду. Превышение любого из лимитов даёт 429. Компания предупреждает, что лимиты сейчас меняются без уведомления.

Повторяет ли SDK Jev запросы сам?

Да. Python и JavaScript SDK по умолчанию делают до двух повторов на кодах 408, 429 и 500–599, учитывают заголовок Retry-After и увеличивают паузу от 0,5 до 5 секунд.

Источники