400 stateful_responses_unsupported: previous_response_id и store в /v1/responses
Ошибка 400 stateful_responses_unsupported означает, что запрос к POST /v1/responses попросил go2llm сохранить или продолжить состояние разговора — полем previous_response_id или store: true, — а шлюз работает как stateless-адаптер поверх chat.completions и никакого состояния между запросами не хранит. Починка одна и та же для обоих полей: отправлять всю историю диалога в input целиком, при каждом запросе заново.
Страница составлена 2026-09-22, обновлена 2026-09-22.
Как выглядит ошибка
Проверено живым запросом 2026-09-22. Запрос с previous_response_id:
curl https://go2llm.tech/v1/responses \
-H "Authorization: Bearer $GO2LLM_API_KEY" \
-H "content-type: application/json" \
-d '{"model":"qwen3-8-flash","input":"ping","previous_response_id":"resp_test123"}'
возвращает статус 400:
{
"error": {
"type": "stateful_responses_unsupported",
"code": "stateful_responses_unsupported",
"message": "previous_response_id is not supported: this gateway stores no response state; send the full history in `input`",
"request_id": "gw_33bd1b88efad4611a5b63bd67638b4a2"
}
}
store: true без previous_response_id даёт тот же код с чуть другим текстом сообщения — оно называет именно то поле, которое отклонено:
{
"error": {
"type": "stateful_responses_unsupported",
"code": "stateful_responses_unsupported",
"message": "store: true is not supported: this gateway stores no response state; send the full history in `input`",
"request_id": "gw_bb33b20417724aec87624b2aa5f5dc77"
}
}
background: true — отдельный код, не stateful_responses_unsupported. Проверено тем же живым прогоном:
{
"error": {
"type": "background_unsupported",
"code": "background_unsupported",
"message": "background: true is not supported: this gateway runs no background jobs, every call is synchronous",
"request_id": "gw_db1c486d2db3489b9840bc8c8851fda0"
}
}
Разница не только в названии кода: stateful_responses_unsupported — про отсутствие памяти между запросами, background_unsupported — про то, что go2llm не выполняет задачи асинхронно, каждый вызов обрабатывается синхронно и полностью в рамках одного HTTP-запроса. У обоих кодов общее свойство: проверка этих полей происходит раньше авторизации — запрос с любым из трёх параметров получает соответствующий 400 даже без ключа или с неверным ключом, до проверки x-api-key/Authorization.
Причины
1. Клиент настроен на «нативный» режим Responses API с сохранением состояния
Responses API у OpenAI изначально спроектирован как опция с состоянием: store: true по умолчанию сохраняет ответ на стороне OpenAI, а previous_response_id продолжает диалог без повторной отправки истории. Клиент, написанный под прямой OpenAI API или мигрировавший с него без изменений, унаследует эти поля в конфигурации по умолчанию.
2. /v1/responses у go2llm — это адаптер протокола, а не отдельный продукт с памятью
go2llm не хранит отдельную базу состояний разговоров под Responses API — /v1/responses транслирует запрос в chat.completions и обратно, обслуживая ровно те же модели, что доступны на этом протоколе. Раз состояние нигде не хранится, previous_response_id физически нечего разрешать в предыдущий контекст, а store: true нечего исполнять.
3. background: true предполагает опрос статуса задачи, которого у go2llm нет
Асинхронный режим Responses API у OpenAI подразумевает, что клиент получает идентификатор задачи и опрашивает её статус отдельными запросами. go2llm обрабатывает вызов целиком синхронно в рамках одного HTTP-соединения — промежуточного состояния «задача выполняется в фоне» не существует, поэтому опрашивать нечего, и параметр отклоняется на входе.
Как починить
Шаг 1. Уберите previous_response_id, store и background из тела запроса целиком — не ставьте их в false/null, а не передавайте вовсе, если клиентская библиотека такое разрешает.
Шаг 2. Передавайте всю историю диалога в input при каждом запросе — так же, как это делается с messages в chat.completions:
from openai import OpenAI
client = OpenAI(api_key="YOUR_API_KEY", base_url="https://go2llm.tech/v1")
history = [
{"role": "user", "content": "Сколько будет 12 * 7?"},
{"role": "assistant", "content": "84"},
{"role": "user", "content": "А если прибавить 16?"},
]
response = client.responses.create(model="qwen3-8-flash", input=history)
print(response.output_text)
Клиент отвечает за накопление истории на своей стороне — точно так же, как при работе с chat.completions. Ответ шлюза usage.cost_usd при этом сохраняется в обычном месте, incремент к биллингу отдельной ветки под Responses API нет.
Шаг 3. Если клиент — Codex CLI, дополнительных правок для истории не нужно: codex exec сам ведёт контекст сессии и отправляет накопленный input при каждом вызове, previous_response_id в штатном режиме работы CLI не требуется. Проверенный живым прогоном конфиг — на странице Codex API.
Шаг 4. Проверьте, что после правки запрос проходит:
curl -s -o /dev/null -w "%{http_code}\n" https://go2llm.tech/v1/responses \
-H "Authorization: Bearer $GO2LLM_API_KEY" \
-H "content-type: application/json" \
-d '{"model":"qwen3-8-flash","input":"Ответь одним словом: работает"}'
Код 200 подтверждает, что причина была именно в отклонённых полях, а не в чём-то ещё.
Чего в Responses API у go2llm нет — честно
Опубликован ровно один режим — синхронный вызов без сохранения состояния. Не работают: previous_response_id, store: true, background: true, а значит и опрос статуса задачи через GET /v1/responses/{id}, которого у go2llm тоже нет. Доступны те же модели, что на chat.completions, и ни одной сверх — модель, у которой в каталоге объявлен только протокол messages, через /v1/responses не отвечает.
Связанные материалы
- 404 на /v1/responses в Codex CLI — более ранняя проблема с тем же endpoint'ом: этот 404 воспроизводился до публикации
/v1/responses2026-09-14, сейчас маршрут есть, и разборstateful_responses_unsupported— следующий шаг после него для тех, кто донастраивает интеграцию. - 404 model_not_found — если модель не отвечает вовсе, а не отклоняет параметры.
- 401 authentication_error — проверка ключа для
/v1/responsesне отличается от других endpoint'ов. - Справочник всех кодов и docs/errors.
FAQ
Можно ли эмулировать previous_response_id на своей стороне? Да — сохраняйте output предыдущего ответа у себя и добавляйте его в input следующего запроса вместе с новым сообщением пользователя, как в примере выше. Это ровно то, что делает Responses API с состоянием за вас на стороне OpenAI, только хранение переносится на клиента.
Почему background: true — это background_unsupported, а не stateful_responses_unsupported, хотя оба про режимы Responses API? Это разные механизмы. previous_response_id и store относятся к сохранению состояния диалога, background — к асинхронному выполнению с опросом статуса. go2llm разделяет их на разные коды ошибок, чтобы клиент мог различить причину отказа по error.code, а не гадать по общему статусу 400.
Списываются ли деньги за запрос, отклонённый с этим кодом? Нет. Проверка полей previous_response_id, store и background происходит раньше резервирования стоимости и даже раньше проверки ключа — 400 по этим полям возвращается до того, как шлюз пытается посчитать стоимость вызова.
Работает ли стриминг в /v1/responses без store и previous_response_id? Да, синхронный режим со стримингом полностью рабочий — ограничение касается только сохранения состояния и фонового выполнения, не самого протокола ответа.
Получить ключ и сделать первый запрос за 3 минуты → go2llm.tech. Цены на все модели — на странице тарифов, инструкции по подключению — в документации.