Ошибки API
Всегда проверяйте HTTP-код и тело ответа. Для части gateway-ошибок объект содержит error.type, error.code, error.message и error.request_id; upstream может вернуть совместимый формат своего протокола.
| HTTP | Код или причина | Что делать |
|---|---|---|
| 400 | invalid_request | проверьте JSON и обязательные поля |
| 400 | unsupported_content_type | удалите image, audio, video, PDF или binary block из текстового запроса |
| 400 | model_protocol_mismatch | выберите endpoint из /v1/models |
| 400 | stateful_responses_unsupported | уберите previous_response_id и store: true, передайте историю в input |
| 401 | no-key | передайте действующий API-ключ |
| 402 | insufficient_balance | пополните баланс или уменьшите max_tokens |
| 403 | model, inactive, expired, ip | проверьте настройки ключа |
| 404 | model_not_found | обновите каталог и скопируйте точный model ID |
| 404 | endpoint_not_found | такого маршрута под /v1/ нет; сверьтесь со списком в error.message |
| 405 | method_not_allowed | маршрут существует, но принимает другой метод — он указан в заголовке allow |
| 409 | idempotency_conflict | не используйте один Idempotency-Key для разных image-запросов |
| 429 | quota, rate_limit | проверьте квоту; учитывайте Retry-After |
| 502 | upstream_unavailable | повторите безопасный текстовый запрос с задержкой |
| 503 | product_paused, no_eligible_route | проверьте /status и повторите позже |
Промах по маршруту
Любой неизвестный путь под /v1/ отвечает JSON того же формата, что и остальные ошибки, а не плейн-текстом — SDK разбирает такой ответ и показывает человеку причину, а не мусор.
curl -i https://go2llm.tech/v1/embeddings
{
"error": {
"type": "invalid_request_error",
"code": "endpoint_not_found",
"message": "/v1/embeddings is not published by this gateway. Available: POST /v1/messages, POST /v1/chat/completions, POST /v1/responses, POST /v1/images/generations, POST /v1/messages/count_tokens, GET /v1/models, GET /v1/models/{id}, GET /v1/me. See https://go2llm.tech/docs/endpoints",
"request_id": "gw_..."
}
}
Если путь опубликован, а метод другой, приходит 405 method_not_allowed с заголовком allow: так опечатка в пути отличима от неверного метода.
curl -i -X GET https://go2llm.tech/v1/messages # 405, allow: POST
OPTIONS к маршрутам, которые берут API-ключ, тоже возвращает 405 — с объяснением, что браузерные вызовы не поддерживаются намеренно: ключ в браузерном бандле читает каждый посетитель. CORS открыт только на публичном чтении каталога, цен и статуса; подробности — в Маршрутах API.
Stateful Responses
POST /v1/responses реализован как stateless-адаптер: шлюз не хранит историю ответов. Поля previous_response_id, store: true и background: true отклоняются с 400 stateful_responses_unsupported и текстом «this gateway stores no response state; send the full history in input» — сообщения API английские. Как перестроить цикл — на странице Responses API.
Request ID
x-go2llm-request-id теперь стоит на всех ответах /v1/*, включая ошибочные и потоковые. У ошибок тот же идентификатор дублируется в теле как error.request_id; префикс — gw_.
curl -sD - -o /dev/null https://go2llm.tech/v1/models | grep -i x-go2llm-request-id
Логируйте этот заголовок на своей стороне: с ним обращение в поддержку разбирается по конкретному запросу, без него — нет.
Прочее
Не повторяйте автоматически media-запрос с ambiguous_upstream_result: поставщик мог принять его. Для поддержки сохраните request_id, но не отправляйте полный API-ключ.
Заголовков X-RateLimit-Remaining и X-RateLimit-Reset шлюз не отдаёт. Retry-After приходит на 429, на 409 request_in_progress и на 503 product_paused; на 502 upstream_unavailable его нет — стратегию повторов стройте сами. Проверить остаток бюджета до длинного прогона, чтобы не получить 402 посреди задачи, можно через GET /v1/me — см. Баланс и расходы.