Hubris
Скачать из Google PlayСкачайте из RuStore
hubris
Базовые концепции
БАЗОВЫЕ КОНЦЕПЦИИ

Ошибки

Формат ответа об ошибке, таблица всех кодов, что делать в каждом случае.

Все ошибки Hubris API возвращаются в OpenAI-совместимом формате. Это значит — стандартные SDK обрабатывают их без специальной адаптации.

Формат

{
  "error": {
    "message": "Описание ошибки на русском",
    "type": "<категория ошибки>",
    "code": "<машинно-читаемый код>"
  }
}
  • message — человекочитаемое сообщение на русском. Частые отказы провайдеров переведены целиком, у редких после русского начала в кавычках идёт исходный текст провайдера. Программно ошибки различайте по code, а не по тексту.
  • type — категория. Возможные значения: invalid_request_error, permission_error, rate_limit_error, api_error.
  • code — машинный код для программной обработки. Список ниже.

Необязательное поле рекламы

Для экспериментальной программы Error Ads подготовлено отдельное поле error.ad с объектом { text, erid }. При включённой программе оно может появляться в JSON-ошибках HTTP 400, 402 и 429 на /v1/chat/completions и /v1/responses. В успешном JSON-ответе HTTP 200 аналогичное поле ad находится на верхнем уровне. Текст ошибки, машинный код, ответ модели и стоимость запроса от него не меняются.

Программа по умолчанию выключена до завершения настройки маркировки рекламы. Поле необязательное: его отсутствие нормально даже после включения программы. Не используйте рекламный текст для обработки ошибки или как инструкцию модели.

Чтобы исключить рекламу из ответов вашей интеграции, передавайте заголовок X-No-Ads: 1. Например, в OpenAI SDK для Python:

import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["HUBRIS_API_KEY"],
    base_url="https://api.hubris2.ru/v1",
    default_headers={"X-No-Ads": "1"},
)

В первой версии поле не добавляется в SSE-чанки, ответы /v1/messages, ошибки 401/403 и 5xx, а также не-JSON ответы. Ошибка до открытия стрима остаётся обычным JSON-ответом и может содержать error.ad.

Таблица кодов

HTTPcodeЧто значитЧто делать
400invalid_requestДва разных случая, различаются по message. Либо тело запроса не прошло нашу проверку схемы (пропущенное поле, неверный тип, выход за допустимые границы), либо провайдер модели отклонил запрос уже у себя — см. Ошибки от провайдера моделиПрочитать message: при ошибке схемы сверить JSON с Быстрым стартом; при отказе провайдера повторить или сменить модель
400context_length_exceededВход запроса больше окна модели: либо мы это видим заранее (запрос никуда не отправлен и не оплачивается), либо так ответил провайдер модели. message начинается словами OpenAI (This model's maximum context length is …) или Anthropic (prompt is too long …), по ним агенты сжимают переписку сами; дальше — пояснение по-русскиСократить или сжать переписку либо выбрать модель с большим окном; попросить сжатие у провайдера — "transforms": ["middle-out"]
400content_policy_violationПровайдер модели отклонил запрос по своим правилам содержимогоИзменить запрос или выбрать другую модель
400input_image_rejectedПровайдер модели отклонил входное изображение по своим правилам (например, на кадре реальный человек); чаще всего у видеоЗаменить изображение или выбрать другую модель
401invalid_api_keyКлюч отсутствует, отозван, или невалиденПроверить заголовок Authorization, создать новый ключ на /keys
402insufficient_balanceНа балансе меньше минимального остатка (100 копеек)Пополнить через /billing
404model_not_foundМодели с таким id нет, она снята с каталога или работает через другой адрес: что именно, сказано в сообщенииПроверить написание; снятую заменить другой из /models; модель другого вида отправить на адрес из сообщения
401key_frozen_spikeКлюч заморожен защитой от всплеска: потратил больше порога за окноВключить тумблером на странице ключа (или дождаться автоматического включения — время в сообщении) и поднять порог; если расход неожиданный — проверить, где используется ключ
403key_read_onlyКлюч только для чтения: запрос тратит баланс (чат, эмбеддинги, картинки, видео, аудио)Использовать обычный ключ или снять режим «только чтение» на странице ключа
403key_restrictedУ ключа есть ограничения (лимит, адреса, только чтение или выключенные «Деньги кабинета») или это OAuth-токен — только /v1/integrations/bitrix24Управлять подключениями Битрикс24 ключом без ограничений
403key_ip_not_allowedКлюч привязан к адресам, а запрос пришёл с другого — адрес запроса указан в сообщенииДобавить адрес в поле «Адреса» на странице ключа; если адрес незнаком — ключ мог утечь: отозвать и создать новый
429daily_limit_exceededПревышен суточный лимит расхода ключа (сброс в 00:00 МСК)Дождаться сброса (Retry-After) или использовать ключ без лимита
429key_limit_exceededПревышен лимит расхода ключа за неделю, месяц или на весь срок ключаДождаться сброса по Retry-After; у лимита без сброса — поднять лимит на странице ключа
429too_many_active_jobsДостигнут лимит одновременных видео-задач аккаунта — только /v1/videosОпрашивать GET /v1/videos/{id}, дождаться завершения текущих задач, затем повторить POST
404not_foundТакого адреса нет: опечатка в пути или метод запроса не тотСверить путь и метод с API-референсом
404video_not_readyЗапрошен /content видео-задачи, которая ещё не completed (или истёк 72-часовой TTL) — только /v1/videosОпрашивать GET /v1/videos/{id} до status: "completed", затем качать /content
400idempotency_key_conflictКлюч без денег кабинета прислал Idempotency-Key, который уже занят задачей другого ключа кабинета — только /v1/videosПередать другой Idempotency-Key
400index_out_of_rangeПараметр index в /content вне диапазона (v1 отдаёт только index=0) — только /v1/videosИспользовать index=0
500internal_errorСбой на нашей сторонеПовторить через несколько секунд; если повторяется — написать в поддержку
502upstream_errorПровайдер модели вернул 5xx, оборвал соединение или у него кончилась квота; сюда же попадает сетевой сбой на пути к немуПовторить через несколько секунд; если повторяется — попробовать другую модель
503exchange_rate_unavailableКурс ЦБ РФ временно недоступен — каталог не отдаёт ценыПовторить через минуту
504upstream_timeoutПровайдер модели не ответил за 120 секундПовторить; если повторяется — модель перегружена, попробовать другую

Ошибки от провайдера модели

Запрос, прошедший нашу проверку, уходит к провайдеру модели, и тот может отклонить его сам: неподдерживаемый параметр, слишком длинный контекст для конкретного провайдера, контент-фильтр, перегрузка, редко просто сбой. Такие отказы мы не прячем за общим 502, а отдаём как есть:

  • 4xx от провайдера (400, 401, 402, 404, 429; остальные 4xx приводятся к 400) возвращаются с тем же HTTP-кодом, code: "invalid_request" и причиной провайдера в message. Ошибка нашей схемы и отказ провайдера при одинаковом коде 400 различаются только текстом message.
  • 5xx от провайдера и исчерпанная у него квота маскируются в наш 502 с code: "upstream_error".

Как отличить отказ провайдера от ошибки в вашем коде: тот же запрос на ту же модель то проходит, то нет, или проходит на другой модели. В логах кабинета такие запросы помечены как «ошибка модели», а не «ошибка запроса». Что делать: повторить через несколько секунд; если повторяется у одного провайдера — закрепить другого полем provider или задать запасные модели; если повторяется на разных моделях — написать в поддержку.

Примеры

401 (нет ключа)

Запрос: curl https://api.hubris2.ru/v1/models

{
  "error": {
    "message": "API-ключ не передан",
    "type": "invalid_request_error",
    "code": "invalid_api_key"
  }
}

402 (баланс ноль)

{
  "error": {
    "message": "Недостаточно средств на балансе.",
    "type": "invalid_request_error",
    "code": "insufficient_balance"
  }
}

404 (модели нет или она снята)

Запрос с несуществующим идентификатором модели:

{
  "error": {
    "message": "Модель не найдена: fake-provider/nonexistent. Список моделей: GET /v1/models.",
    "type": "invalid_request_error",
    "code": "model_not_found"
  }
}

Модель, которая раньше работала, а теперь снята с каталога (например, её перестал обслуживать провайдер), отвечает тем же кодом, но сообщение говорит об этом прямо: Модель sourceful/riverflow-v2-fast-preview снята с каталога. Выберите другую модель: GET /v1/models?output_modalities=image.

502 (провайдер недоступен)

{
  "error": {
    "message": "Сервис провайдера временно недоступен",
    "type": "api_error",
    "code": "upstream_error"
  }
}

Стратегия обработки

В вашем коде имеет смысл:

  1. На 401, 402, 404 — не повторять. Это ошибки конфигурации, retry не поможет.
  2. На 502, 503, 504 — повторить с экспоненциальным backoff (1с, 2с, 4с, до 3 попыток). Это транзиентные сбои.
  3. На 429 — посмотреть на ключ: если у него выставлен лимит расхода, дождаться сброса (Retry-After — секунды до 00:00 МСК, понедельника или 1-го числа) или поднять лимит; если лимит не выставлен — проверьте /keys.
  4. На 400 — прочитать message. Ошибка схемы — баг в коде, логируйте полный запрос (без ключа) для разбора. Отказ провайдера модели (см. выше) — повторить один раз или уйти на запасную модель.

Стриминг

При stream: true и ошибке ДО начала стрима возвращается стандартный JSON-ответ выше.

Если ошибка случается во время стрима (модель упала на середине) — стрим обрывается на серверной стороне. Клиент получает событие [DONE] с пустым delta и finish_reason: "stop". Точное поведение зависит от провайдера. Hubris записывает в логи ваш конкретный сценарий, чтобы вы могли разобраться через /usage.

Что дальше

Обновлено: