Skip to content

OpenAI previous_response_not_found: Причины и способы устранения ​

Вы пытаетесь продолжить диалог в Responses API с помощью previous_response_id и получаете HTTP 400: "Previous response with id 'resp_…' not found." Ниже описано, что нужно API для разрешения этого ID, пять ситуаций, когда это невозможно, и шаблон работы без сохранения состояния (stateless), который позволяет избежать этой ошибки.

Краткий ответ

Ошибка previous_response_not_found означает, что API не может загрузить ответ, на который вы ссылаетесь, и поэтому не может восстановить предыдущий контекст. Типичные причины: исходный вызов был выполнен с параметром store: false (или в рамках политики Zero Data Retention), ответ старше 30 дней, он был удален или ID получен от другого провайдера или аккаунта. Надежное решение — перестать зависеть от состояния на стороне сервера: храните диалог самостоятельно, отправляйте полный набор входных данных для каждого шага с store: false и передавайте состояние рассуждений через encrypted_content.

Симптомы и значение ошибки ​

Тело ответа, возвращаемое Python SDK от OpenAI:

json
{
  "error": {
    "message": "Previous response with id 'resp_abc123' not found.",
    "type": "invalid_request_error",
    "param": "previous_response_id",
    "code": "previous_response_not_found"
  }
}

В руководстве по кодам ошибок OpenAI previous_response_not_found описывается как невозможность разрешения previous_response_id из доступного состояния. Это критическая ошибка: API не продолжит работу без этого контекста, а повторные запросы с тем же ID приводят к тому же результату.

Схожая ошибка возникает, если вы воспроизводите выходные элементы, содержащие серверные ID, при отключенном параметре store:

text
Item with id 'rs_…' not found. Items are not persisted when `store` is set to false. Try again with `store` set to true, or remove this item from your input.

Причина та же — вы ссылаетесь по ID на то, что не было сохранено, — и решение также описано ниже.

Почему это происходит ​

  1. Исходный ответ был создан с store: false. По умолчанию store имеет значение true, если оно не указано, но многие клиенты и фреймворки устанавливают false из соображений конфиденциальности. Ответ, который не был сохранен, нельзя использовать в дальнейшем. Это часто встречается в трекере проблем SDK агентов OpenAI, когда сессия выполнялась с store=False, а последующий шаг пытался выстроить цепочку на её основе.
  2. Zero Data Retention (ZDR). В руководстве OpenAI по управлению данными указано, что при включенном режиме ZDR параметр store всегда обрабатывается как false, даже если в запросе установлено true, поэтому цепочки запросов в организациях с ZDR никогда не работают.
  3. Истек срок хранения. Объекты Response по умолчанию хранятся 30 дней. Задача, которая возобновляет поток после этого периода, получит данную ошибку.
  4. Ответ был удален. Если ваш код (или задача по очистке) удаляет ответы, их ID становятся невалидными.
  5. ID был получен из другого источника. ID ответа имеет смысл только для той службы, которая его создала. ID от api.openai.com, отправленный на шлюз; ID от одного шлюза, отправленный другому; или балансировщик нагрузки, который перенаправляет второй шаг диалога другому провайдеру, — всё это приведет к ошибке. В документации OpenAI не уточняется область видимости аккаунта для сохраненных ответов, поэтому считайте каждый ID приватным для того ключа и той конечной точки, которые его сгенерировали.

Также обратите внимание, что previous_response_id нельзя комбинировать с параметром conversation — используйте один механизм управления состоянием на запрос.

Решение 1: Отправляйте полный набор входных данных самостоятельно (режим Stateless) ​

Этот подход работает везде: вы владеете историей, и каждый запрос несет её в себе целиком.

python
from openai import OpenAI

client = OpenAI(api_key="sk-YOUR_TOKEN", base_url="https://byesu.com/v1")

history = [{"role": "user", "content": "Plan a migration from REST polling to webhooks."}]

resp = client.responses.create(
    model="gpt-6.1-sol",
    input=history,
    store=False,
    include=["reasoning.encrypted_content"],   # безвредно там, где это уже значение по умолчанию
)
print(resp.output_text)

# Переносим выходные элементы модели (сообщения, рассуждения, вызовы инструментов) на следующий шаг
history += resp.output
history.append({"role": "user", "content": "Now list the risks."})

resp = client.responses.create(
    model="gpt-6.1-sol",
    input=history,
    store=False,
    include=["reasoning.encrypted_content"],
)
print(resp.output_text)

Почему это работает:

  • Нечего искать. Без previous_response_id нет состояния на стороне сервера, которое могло бы потеряться.
  • Рассуждения (reasoning) сохраняются. В руководстве OpenAI по рассуждениям указано, что в режиме без сохранения состояния (store: false или ZDR) элементы рассуждений по умолчанию включают свойство encrypted_content; передача этих элементов обратно позволяет модели продолжать рассуждения. API по-прежнему принимает reasoning.encrypted_content в параметре include для совместимости.
  • Циклы инструментов (tool loops) остаются неизменными. Для вызова функций добавляйте элементы вызова функций модели и элементы function_call_output в history точно так же, как вы делали бы это в любом цикле без сохранения состояния.

Если провайдер отклоняет воспроизведенные элементы с сообщением "Item with id … not found" (как указано выше), удалите поле id из этих элементов перед отправкой — такая ошибка сообщалась для некоторых прокси-серверов без сохранения состояния в трекере Codex от OpenAI.

Примечание о стоимости: это не дороже по токенам, чем использование цепочек. Руководство OpenAI по состоянию диалогов гласит, что при использовании previous_response_id все предыдущие входные токены в цепочке всё равно оплачиваются как входные. Длинные истории в любом случае увеличивают расход — см. превышение контекстного окна для получения информации об обрезке и сжатии, что также работает при store: false.

Решение 2: Автоматический переход к безсостоятельному режиму при сбое цепочки ​

Если вы хотите использовать previous_response_id там, где это работает (например, в OpenAI с включенным хранилищем), всё равно ведите локальную копию истории и переключайтесь на неё, если ID не удается разрешить:

python
import openai

def continue_turn(prev_id, history, new_user_msg, model="gpt-6-sol"):
    history.append({"role": "user", "content": new_user_msg})
    try:
        resp = client.responses.create(
            model=model,
            previous_response_id=prev_id,
            input=[{"role": "user", "content": new_user_msg}],
        )
    except openai.BadRequestError as e:
        if getattr(e, "code", None) != "previous_response_not_found":
            raise
        # Цепочка разорвана: воспроизводим весь диалог без сохранения состояния
        resp = client.responses.create(
            model=model,
            input=history,
            store=False,
            include=["reasoning.encrypted_content"],
        )
    history += resp.output
    return resp

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

Решение 3: Не выстраивайте цепочки через разных провайдеров ​

Если ваш трафик может перемещаться между конечными точками — например, при отказоустойчивости между OpenAI и шлюзом, использовании нескольких шлюзов или маршрутизатора, который выбирает провайдера для каждого запроса, — previous_response_id от одного звена не разрешится на другом. Шлюзы могут вообще не сохранять ответы или направлять последующие запросы другому вышестоящему сервису, поэтому не полагайтесь на previous_response_id при работе с несколькими провайдерами. Используйте шаблон без сохранения состояния из Решения 1 для любой конфигурации с несколькими провайдерами.

Если вы работаете напрямую с OpenAI и хотите получить надежное серверное состояние, Conversations API предоставляет долгоживущий ID диалога; OpenAI отмечает, что элементы диалога не подпадают под 30-дневный срок хранения. Это всё равно привязано к конкретному провайдеру, поэтому ограничение по переносимости остается в силе.

Codex и другие клиентские агенты ​

Агенты для программирования сталкиваются с этой проблемой, когда предполагают наличие состояния на сервере. История OpenAI Codex — полезный пример:

  • Оригинальный Codex CLI добавил опцию disable_response_storage для организаций с политикой ZDR, чтобы клиент сохранял элементы ответов самостоятельно.
  • В сентябре 2025 года в PR #3212 ("Never store requests") эта опция была удалена из Codex, а последующие изменения установили store: false для каждого запроса Responses. Текущий Codex хранит историю локально и воспроизводит её с зашифрованными рассуждениями, поэтому он не зависит от previous_response_id по HTTP. Старые руководства и конфигурации, в которых всё ещё есть disable_response_storage = true, относятся к тому раннему периоду; текущие релизы больше не читают эту опцию.
  • Исходный код Codex действительно использует previous_response_id в своем транспорте WebSocket для Responses. Для пользовательских провайдеров параметр supports_websockets по умолчанию равен false; оставьте его выключенным, если провайдер явно не поддерживает режим Responses WebSocket.

Руководство byesu по Codex CLI показывает рабочий конфиг провайдера для https://byesu.com/v1.

Если вы вызываете GPT через byesu ​

byesu — это API-шлюз для ИИ с OpenAI-совместимой конечной точкой https://byesu.com/v1, поддерживающий как Chat Completions, так и Responses, с оплатой по факту использования без подписки.

  • Предпочитайте запросы без сохранения состояния. Отправляйте полный ввод с store: false, как в Решении 1; это работает одинаково на любой OpenAI-совместимой конечной точке и полностью устраняет данный класс ошибок.
  • Никогда не используйте ID повторно между конечными точками. ID вида resp_…, созданный у другого провайдера, здесь не разрешится, и наоборот — сохраняйте свою собственную историю для всего, что может переключаться между конечными точками.

Чтобы начать работу, следуйте Quick Start.

Часто задаваемые вопросы ​

Что означает ошибка previous_response_not_found? ​

Это ошибка 400 invalid_request_error с параметром previous_response_id. API Responses не смог найти переданный вами ID в доступном ему состоянии, поэтому он не может продолжить цепочку. Генерация не происходит; повторные попытки с тем же ID приводят к той же ошибке.

Почему мой ID ответа не найден сразу после его создания? ​

Чаще всего исходный запрос был выполнен с параметром store, установленным в false, поэтому ответ не был сохранен. Организации с политикой Zero Data Retention обрабатываются как store: false, даже если вы отправляете true. Другая распространенная причина — отправка ID другому провайдеру или на конечную точку, отличную от той, которая его создала.

Как долго хранятся ответы Responses API? ​

OpenAI по умолчанию хранит объекты Response в течение 30 дней, если параметр store установлен в true (это значение по умолчанию, если параметр опущен). По истечении этого срока ID больше нельзя использовать в previous_response_id. Элементы, добавленные в объект Conversation, не подпадают под 30-дневный срок хранения (TTL).

Как продолжить диалог без previous_response_id? ​

Храните историю диалога самостоятельно: добавляйте выходные элементы каждого ответа в свой список ввода и отправляйте полный список в каждом запросе с параметром store, установленным в false. Элементы рассуждений в этом случае содержат encrypted_content, поэтому состояние рассуждений сохраняется между итерациями без необходимости хранения чего-либо на стороне сервера.

Нужен ли Codex параметр disable_response_storage? ​

Эта опция была удалена из кодовой базы Codex в сентябре 2025 года (openai/codex PR #3212), и текущий Codex отправляет store: false в каждом запросе Responses. Codex хранит историю локально и повторно отправляет её, поэтому он не зависит от previous_response_id по протоколу HTTP.

Возникла проблема? Напишите в поддержку или в наш чат.