Документация API go2llm

502 upstream_unavailable и 503: как правильно ретраить

Ошибки 502 и 503 означают, что запрос не дошёл до модели по вине поставщика или маршрута, а не по вине вашего кода. go2llm возвращает 502 upstream_unavailable с сообщением all safe upstream attempts failed и 503 с кодами product_paused или no_eligible_route. Оба статуса безопасно ретраить — но только для текстовых запросов и только до первого байта SSE-стрима.

Страница составлена 2026-09-11, обновлена 2026-09-11.

Как выглядит ошибка

go2llm на исчерпании безопасных попыток к поставщикам отдаёт 502:

{
  "error": {
    "type": "upstream_unavailable",
    "code": "upstream_unavailable",
    "message": "all safe upstream attempts failed",
    "request_id": "gw_5e0c92a1d7b3486fa4e18c05b2d7f639"
  }
}

Второй вариант того же класса — когда маршрута нет вовсе, статус 503:

{
  "error": {
    "type": "upstream_unavailable",
    "code": "upstream_unavailable",
    "message": "no upstream route is currently available",
    "request_id": "gw_af71b3e2c5d8420e93a6f10d7c4b2e58"
  }
}

Третий вариант — маршрут есть, но ни один не проходит по условиям запроса: 503 с типом no_eligible_route и сообщением no qualified compatible route is available.

Четвёртый — плановая пауза продукта: 503 с типом product_paused, заголовок retry-after: 60.

Официальный Anthropic API в аналогичных ситуациях отвечает нестандартным статусом 529 с типом overloaded_error — это перегрузка на стороне Anthropic, и обрабатывать её нужно так же, как 503. OpenAI API отдаёт 503 service_unavailable.

Причины 502 и 503

1. Поставщик не ответил или ответил ошибкой на все безопасные попытки

go2llm держит несколько маршрутов к одной модели и до начала ответа может использовать совместимый fallback-маршрут на разрешённых классах ошибок. Сообщение all safe upstream attempts failed означает, что все такие попытки исчерпаны — то есть проблема шире одного поставщика.

2. Для модели нет доступного маршрута прямо сейчас

no upstream route is currently available — маршрут к запрошенной модели временно отсутствует. Проверка занимает один запрос без ключа: GET https://go2llm.tech/status.

3. Маршруты есть, но ни один не подходит под запрос

no_eligible_route возникает, когда доступные маршруты не удовлетворяют условиям запроса. Практический шаг — попробовать соседнюю модель того же протокола: claude-sonnet-5 вместо claude-opus-5 на POST /v1/messages, gpt-5.6-terra вместо gpt-6-astra на POST /v1/chat/completions.

4. Продукт на паузе

product_paused — go2llm сознательно приостановил обслуживание направления. Шлюз ставит retry-after: 60, то есть повтор имеет смысл не раньше чем через минуту.

5. Перегрузка у самого вендора

Anthropic API возвращает 529 overloaded_error в часы пиковой нагрузки. Это не ошибка вашего запроса и не ошибка шлюза; лечится ожиданием и, при затяжной перегрузке, переключением на другую модель.

6. Клиентский таймаут короче времени генерации

Ответ на 4000 выходных токенов у крупной модели может занимать десятки секунд. Таймаут HTTP-клиента в 10 секунд разрывает соединение, и приложение видит сетевую ошибку, внешне похожую на 502, хотя go2llm запрос обрабатывал. Ставьте таймаут не меньше 120 секунд для нестримовых запросов.

Как починить по шагам

Шаг 1. Посмотрите GET https://go2llm.tech/status — endpoint работает без ключа и показывает состояние шлюза.

Шаг 2. Определите, можно ли ретраить. Безопасно повторять: текстовые запросы к POST /v1/messages и POST /v1/chat/completions на 429, 502, 503 и сетевых таймаутах. Нельзя повторять автоматически: media-запрос, вернувший ambiguous_upstream_result, — поставщик мог его принять, и повтор спишет деньги дважды. Нельзя повторять SSE-стрим после первого валидного события — go2llm не переключает маршрут после первого байта, а клиентский ретрай даст дублирующий ответ.

Шаг 3. Внедрите backoff с jitter и потолком. Рабочая реализация под коды go2llm:

import random, time
import httpx

RETRYABLE_STATUS = {429, 502, 503, 529}   # 529 — overloaded_error у Anthropic
NEVER_RETRY_CODES = {"quota", "ambiguous_upstream_result"}

def call_text(payload, api_key, *, max_attempts=6, base=1.0, cap=32.0, timeout=120.0):
    """Повтор текстового запроса к go2llm на 429/502/503 с экспоненциальным backoff."""
    last = None
    with httpx.Client(timeout=timeout) as client:
        for attempt in range(max_attempts):
            try:
                r = client.post(
                    "https://go2llm.tech/v1/chat/completions",
                    headers={"Authorization": f"Bearer {api_key}"},
                    json=payload,
                )
            except (httpx.TimeoutException, httpx.TransportError) as exc:
                last, status, code, msg = exc, None, "network", str(exc)
            else:
                if r.status_code < 400:
                    return r.json()
                err = r.json().get("error", {})
                if not isinstance(err, dict):
                    err = {"message": str(err)}
                status = r.status_code
                code = err.get("code") or err.get("type")
                msg = err.get("message")
                last = RuntimeError(
                    f"{status} {code}: {msg} [request_id={err.get('request_id')}]"
                )
                if code in NEVER_RETRY_CODES or status not in RETRYABLE_STATUS:
                    raise last
                hint = r.headers.get("retry-after")
                if hint and hint.isdigit():
                    time.sleep(float(hint) * (0.5 + random.random() / 2))
                    continue

            if attempt == max_attempts - 1:
                raise last if isinstance(last, Exception) else RuntimeError(msg)
            delay = min(cap, base * 2 ** attempt)
            time.sleep(delay * (0.5 + random.random() / 2))   # jitter 50–100%

Шесть попыток с базой 1 секунда и потолком 32 секунды дают до ~47 секунд суммарного ожидания. Для фоновых задач поднимайте max_attempts до 8 и cap до 60 секунд, для интерактивных — опускайте до 3 попыток и cap 8 секунд.

Шаг 4. Если 502 повторяется больше пяти минут — отправьте error.request_id (он начинается с gw_) в support@go2llm.tech или Telegram @go2llm_support. Request logs go2llm хранятся до 90 дней и содержат маршрут, usage, стоимость, статус и очищенную ошибку; промпты и ответы в продуктовые логи не пишутся.

Как избежать 502 и 503 в будущем

Держите fallback-модель того же протокола и переключайтесь на неё после второго 502 подряд. На POST /v1/messages парой идут claude-opus-5 ($0.50 / $2.51 / $0.05 за 1M) и claude-sonnet-5 ($0.33 / $1.64 / $0.033) — код не меняется, меняется строка модели. На POST /v1/chat/completions — gpt-6-astra и gpt-5.6-sol ($0.40 / $2.01 / $0.04).

Разделяйте таймауты: 120 секунд на нестримовый запрос и отдельный, более длинный, на стрим. Слишком короткий таймаут создаёт ложные 502 в ваших метриках и мешает отличить проблему поставщика от проблемы клиента.

Не ретрайте всё подряд. 400, 401, 402, 403, 404 и 409 при повторе вернут тот же ответ, а лимит 20 RPM на ключ израсходуется впустую. Ветвитесь по error.code, а не по HTTP-статусу: под одним 429 у go2llm живут ретраибельный rate_limit и неретраибельный quota.

Считайте деньги: неудачный запрос к go2llm не списывает ничего — шлюз резервирует оценку до вызова и освобождает резерв, баланс не уходит ниже нуля. Стоимость успешного запроса приходит в usage.cost_usd, в том числе в финальном usage-блоке SSE.

Связанные ошибки

FAQ

Чем 502 отличается от 503 в go2llm? 502 upstream_unavailable с сообщением all safe upstream attempts failed означает, что попытки к поставщикам были и все провалились. 503 означает, что подходящего маршрута не нашлось вовсе: no upstream route is currently available, no_eligible_route или плановая пауза product_paused с заголовком retry-after: 60.

Можно ли повторить оборвавшийся SSE-стрим? Нет, если уже получено хотя бы одно валидное SSE-событие. go2llm может подобрать совместимый fallback-маршрут только до первого байта ответа; после этого переключение не выполняется, и повтор на клиенте даст дублирующую генерацию и второе списание.

Что делать с ambiguous_upstream_result? Не повторять автоматически. Этот результат означает, что поставщик мог принять media-запрос, и автоматический ретрай приведёт к двойной оплате. Проверьте результат вручную и при необходимости отправьте новый запрос с новым Idempotency-Key.

Anthropic возвращает 529 — это ошибка go2llm? Нет. Статус 529 overloaded_error — нестандартный код самого Anthropic API, означающий перегрузку на их стороне. Обрабатывайте его в той же ветке, что 503: экспоненциальный backoff с jitter, при затяжной перегрузке — переключение на другую модель.


Получить ключ и сделать первый запрос за 3 минуты → go2llm.tech. Состояние шлюза — GET /status, подключение — в документации, цены — на странице тарифов.