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

504 gateway timeout: почему у go2llm на его месте 502

504 Gateway Timeout означает, что какой-то прокси или балансировщик в цепочке между вами и сервером не получил ответ от следующего звена в пределах своего собственного таймаута. Это ошибка инфраструктуры, а не формат ответа модели — ни OpenAI, ни Anthropic не описывают 504 как часть своего API так, как описывают 400 или 429, потому что обычно 504 возвращает не сама модель, а что-то перед ней: CDN, балансировщик, ваш собственный обратный прокси. На go2llm ситуация конкретнее: у шлюза есть собственный таймаут запроса к поставщику — 180 000 мс на большинстве маршрутов, 60 000 мс на части. Что происходит при его срабатывании, зависит от того, включён ли роутер провайдеров. При включённом роутере таймаут даёт 502 с кодом timeout, а настоящая 504 от самого вендора доходит до клиента буквальной 504 с кодом upstream_http_504 — роутер делает одну попытку на запрос и ретранслирует статус поставщика как есть. При выключенном роутере оба случая сворачиваются в один и тот же обобщённый 502 upstream_unavailable с сообщением all safe upstream attempts failed — кода timeout на этом пути не бывает вовсе, потому что старый код сначала пробует другие маршруты и сообщает один общий отказ, когда они все исчерпаны. Какой режим сейчас включён на go2llm.tech, видно без ключа: curl -s https://go2llm.tech/status, поле providerRouterV1 — сегодня там true, но это текущая настройка, а не обещание навсегда, проверяйте сами.

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

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

Классический 504 от инфраструктурного прокси выглядит не как JSON вендора, а как страница или короткий текст самого прокси — nginx, Cloudflare или корпоративный шлюз показывают свою собственную страницу ошибки, без error.type и без request_id в привычном для LLM API виде.

go2llm при срабатывании собственного таймаута upstream-запроса, если включён роутер провайдеров, отдаёт статус 502 с кодом timeout:

{
  "error": {
    "type": "upstream_error",
    "code": "timeout",
    "message": "The upstream model is temporarily unavailable. Retry the request (request_id: gw_5e0c92a1d7b3486fa4e18c05b2d7f639).",
    "request_id": "gw_5e0c92a1d7b3486fa4e18c05b2d7f639"
  }
}

При выключенном роутере тот же самый таймаут выглядит иначе — отдельного кода на этот случай нет, только общий конверт отказа апстрима:

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

Буквальная 504 с тем же конвертом тоже возможна — при включённом роутере провайдеров: он делает одну попытку на запрос и ретранслирует статус поставщика как есть, поэтому настоящий таймаут на стороне вендора приходит клиенту как есть — статус 504, код upstream_http_504. Такое случается редко, вендоры сами отдают 504 нечасто, но это уже не объясняется чужим прокси. При выключенном роутере этот случай, как и собственный таймаут go2llm, сворачивается в тот же 502 upstream_unavailable — по коду их не различить.

Если ваш HTTP-клиент вообще не дожил до ответа и выбросил исключение по своему собственному таймауту — ReadTimeout, TimeoutError — это не HTTP-статус 504 вовсе, а обрыв соединения на вашей стороне раньше, чем сервер успел ответить хоть что-нибудь. Такие обрывы в логах иногда описывают словами «таймаут шлюза», хотя формально никакого HTTP-ответа 504 не было получено. Отличить обрыв на своей стороне и честную 504 от go2llm просто: у ответа шлюза всегда есть error.type/error.code/request_id, у обрыва клиента — никакого HTTP-ответа вовсе.

Причины

1. Таймаут собственного HTTP-клиента короче времени генерации

Самая частая причина на практике. Библиотека или ваш код ставит таймаут в 10–30 секунд по умолчанию, а модель на длинный ответ отвечает дольше. Клиент рвёт соединение сам, до получения любого ответа, и это чаще всего маскируется под «таймаут», хотя формально никакого 504 от сервера не было.

2. Собственный прокси перед go2llm настроен строже, чем реальное время ответа

Если между вашим приложением и go2llm стоит свой обратный прокси или балансировщик, у него обычно есть собственный таймаут на ответ от бэкенда — proxy_read_timeout в nginx, idle timeout у балансировщика облака. go2llm при этом может легитимно отвечать до 180 секунд на большинстве маршрутов, и прокси с таймаутом в 30 или 60 секунд отдаст 504 вашему собственному фронтенду раньше, чем go2llm вообще закончит попытку.

3. Таймаут upstream-запроса самого go2llm истёк

go2llm ограничивает время ожидания ответа от поставщика — 180 000 мс на большинстве маршрутов, 60 000 мс на части. Если это время истекло до того, как поставщик хоть что-то ответил, клиент получает 502 — с кодом timeout, когда включён роутер провайдеров, или с общим кодом upstream_unavailable, когда он выключен. В обоих случаях это отдельно от кода upstream_http_5xx, под которым при включённом роутере ретранслируется настоящий ответ поставщика (разбор рядом: 500 internal server error).

4. Сторонний прокси или CDN перед go2llm или перед прямым API вендора

Корпоративная сеть, VPN-шлюз или CDN на пути к любому внешнему хосту иногда сами возвращают 504, если origin отвечает медленно — это не связано с go2llm или вендором напрямую, а с инфраструктурой, через которую идёт трафик до них.

5. Стриминг заменён на ожидание одного большого ответа

Не-стримовый запрос держит соединение открытым без единого байта до самого конца генерации, и любой промежуточный таймер по неактивности воспринимает эту паузу как повод разорвать соединение. Стриминг (stream: true) присылает первые байты почти сразу и заметно реже утыкается в такие таймеры.

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

Шаг 1. Проверьте, был ли это реальный HTTP-ответ 504 или обрыв соединения на клиенте. Если исключение вида ReadTimeout или TimeoutError — это ваш собственный таймаут, а не ответ сервера:

import httpx

try:
    r = httpx.post(
        "https://go2llm.tech/v1/chat/completions",
        headers={"Authorization": f"Bearer {api_key}"},
        json=payload,
        timeout=200.0,  # с запасом выше 180 секунд
    )
    print(r.status_code, r.json())
except httpx.TimeoutException:
    print("это клиентский таймаут, а не HTTP 504 от сервера")

Шаг 2. Если между вашим приложением и go2llm стоит свой прокси — сверьте его таймаут с известным таймаутом go2llm и держите свой заметно выше 180 секунд:

location /llm/ {
    proxy_pass https://go2llm.tech/;
    proxy_read_timeout 200s;
    proxy_connect_timeout 10s;
}

Шаг 3. Для длинных ответов переключитесь на стриминг — это не устраняет таймаут как явление, но снижает шанс упереться в промежуточные ограничения по неактивности соединения:

import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://go2llm.tech/v1",
  apiKey: process.env.GO2LLM_API_KEY,
});

const stream = await client.chat.completions.create({
  model: "gpt-5.6-luna",
  stream: true,
  messages: [{ role: "user", content: "Длинный ответ по шагам" }],
});

for await (const chunk of stream) {
  process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}

Шаг 4. Если фактический ответ от go2llm — это 502 с кодом timeout, буквальная 504 с кодом upstream_http_504, либо обобщённый 502 upstream_unavailable (дороутерный путь — код на нём один на все причины), а не что-то на вашей стороне, применяйте тот же backoff, что и для остальных причин 502/5xx — подробный код с Retry-After на странице 502 upstream_unavailable и 503. Распознавайте отказ по статусу (>= 500) и по коду — timeout, upstream_unavailable или что угодно вида upstream_http_... — а не по одному конкретному значению: какой из них придёт, зависит от режима роутера на сервере, а не от вашего клиента. Ретраить нельзя, если это произошло уже после первого валидного события SSE-потока — переключение маршрута после первого байта go2llm не делает.

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

Ставьте таймаут своего HTTP-клиента заметно выше 180 секунд для нестримовых запросов к go2llm — например, 200–240 секунд с запасом, а не значение по умолчанию из библиотеки. Если в цепочке есть свой прокси или балансировщик, синхронизируйте его таймаут с этим же числом: самое короткое звено в цепочке определяет, что увидит конечный пользователь. Для всего, что может занять больше нескольких секунд генерации, используйте стриминг — он и снижает риск обрыва по неактивности, и даёт пользователю первые слова ответа раньше, чем весь текст будет готов. В повторных попытках распознавайте отказ и по статусу (>= 500), и по коду — timeout, upstream_unavailable или что угодно, начинающееся с upstream_http_, — а не по одному конкретному значению: какой код придёт, зависит от режима роутера на сервере, а не от вашего клиента.

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

FAQ

Может ли go2llm вернуть буквально статус 504? Да, когда сам поставщик отвечает 504 и при этом включён роутер провайдеров (проверить — curl -s https://go2llm.tech/status, поле providerRouterV1) — редко, вендоры сами отдают этот статус нечасто, но при включённом роутере он ретранслируется как есть, с кодом upstream_http_504. Собственный таймаут upstream-запроса у go2llm (180 секунд на большинстве маршрутов, 60 секунд на части) — другое дело: при включённом роутере это 502 с кодом timeout, при выключенном — тот же 502, но с общим кодом upstream_unavailable, как и буквальная 504 от вендора в этом режиме. Буквальной 504 таймаут go2llm не даёт ни в одном из режимов.

Почему таймаут go2llm нигде не был объявлен раньше? Точные значения таймаута — 180 000 мс на большинстве маршрутов и 60 000 мс на части — не были опубликованы отдельной страницей до этого материала. Это внутренняя настройка шлюза, а не зафиксированное публичное обязательство, и она может измениться без отдельного объявления.

Что делать, если 504 приходит стабильно, а не изредка? Если это 504 без JSON-конверта go2llm, с высокой вероятностью дело в вашем собственном прокси или библиотеке с таймаутом короче реального времени генерации: при собственном таймауте у go2llm всегда 502, а не 504. Но если 504 приходит именно с конвертом go2llm (error.type/error.code/request_id) и кодом upstream_http_504, стабильное повторение означает, что у поставщика систематически рвётся его собственный ответ, — это инцидент на стороне вендора, а не вашей сети. Конверт в теле и подскажет, какой из двух случаев у вас.

Стриминг гарантированно решает эту проблему? Нет, гарантии нет — стриминг снижает вероятность обрыва по неактивности соединения, потому что байты идут почти сразу, но не отменяет таймауты, привязанные к общей продолжительности запроса, если такие настроены на вашей стороне отдельно.


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