OpenAI previous_response_not_found: Causes and Fixes
You continue a Responses API conversation with previous_response_id and get HTTP 400: "Previous response with id 'resp_…' not found." Here is what the API needs in order to resolve that ID, the five situations where it can't, and the stateless pattern that avoids the error.
Quick answer
previous_response_not_found means the API cannot load the response you referenced, so it cannot rebuild the earlier context. The usual causes: the original call ran with store: false (or under Zero Data Retention), the response is older than the 30-day retention, it was deleted, or the ID came from a different provider or account. The durable fix is to stop depending on server-side state: keep the conversation yourself, send the full input each turn with store: false, and carry reasoning forward via encrypted_content.
Symptoms and What the Error Means
The body, as raised by OpenAI's Python SDK:
{
"error": {
"message": "Previous response with id 'resp_abc123' not found.",
"type": "invalid_request_error",
"param": "previous_response_id",
"code": "previous_response_not_found"
}
}OpenAI's error-code guide describes previous_response_not_found as a previous_response_id that cannot be resolved from available state. It is a hard failure: the API won't continue without that context, and retrying with the same ID gives the same result.
A closely related failure happens when you replay output items that carry server IDs while store is off:
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.Same root cause — you referenced something by ID that was never saved — and the same fix below.
Why It Happens
- The original response was created with
store: false.storedefaults totruewhen omitted, but many clients and frameworks set it tofalsefor privacy. A response that was never stored can't be referenced later. This shows up in OpenAI's agents SDK issue tracker when a session ran withstore=Falseand a later step tried to chain from it. - Zero Data Retention. OpenAI's data-controls guide says that under ZDR the
storeparameter is always treated asfalse, even if the request sets it totrue— so chaining never works in a ZDR organization. - Retention expired. Response objects are kept for 30 days by default. A job that resumes a thread after that window will hit this error.
- The response was deleted. If your code (or a cleanup job) deletes responses, their IDs become unresolvable.
- The ID came from somewhere else. A response ID only means something to the service that created it. An ID from
api.openai.comsent to a gateway, an ID from one gateway sent to another, or a load balancer that sends turn two to a different provider than turn one — all fail. OpenAI's docs don't spell out the exact account scope of stored responses, so treat each ID as private to the key and endpoint that produced it.
Also note that previous_response_id cannot be combined with the conversation parameter — use one state mechanism per request.
Fix 1: Send the Full Input Yourself (Stateless Mode)
This is the approach that works everywhere: you own the history, and every request carries all of it.
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"], # harmless where it's already the default
)
print(resp.output_text)
# Carry the model's output items (messages, reasoning, tool calls) forward
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)Why this works:
- Nothing to look up. With no
previous_response_id, there is no server-side state to go missing. - Reasoning still carries over. OpenAI's reasoning guide says that in stateless mode (
store: falseor ZDR), reasoning items include anencrypted_contentproperty by default; passing those items back lets the model continue its reasoning. The API still acceptsreasoning.encrypted_contentinincludefor compatibility. - Tool loops are unchanged. For function calling, append the model's function-call items and your
function_call_outputitems tohistoryexactly as you would in any stateless loop.
If a provider rejects replayed items with the "Item with id … not found" message above, strip the id field from replayed items before sending — that error has been reported for some stateless proxy setups in OpenAI's Codex tracker.
Cost note: this is not inherently more expensive in tokens than chaining. OpenAI's conversation-state guide states that with previous_response_id, all previous input tokens in the chain are still billed as input tokens. Long histories grow either way — see context length exceeded for trimming and compaction, which also works with store: false.
Fix 2: Fall Back Automatically When Chaining Fails
If you want to keep previous_response_id where it works (for example on OpenAI with storage on), keep a local copy of the history anyway and fall back to it when the ID can't be resolved:
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
# Chain is gone: replay the whole conversation statelessly
resp = client.responses.create(
model=model,
input=history,
store=False,
include=["reasoning.encrypted_content"],
)
history += resp.output
return respWithout the local copy there is nothing to fall back to — the earlier turns were only on the server that just told you it doesn't have them.
Fix 3: Don't Chain Across Providers
If your traffic can move between endpoints — failover between OpenAI and a gateway, multiple gateways, or a router that picks per request — a previous_response_id from one leg will not resolve on another. Gateways may not persist responses at all, or may route a follow-up to a different upstream, so don't rely on previous_response_id across providers. Use the stateless pattern from Fix 1 for any multi-provider setup.
If you are on OpenAI directly and want durable server-side state, the Conversations API gives you a long-lived conversation ID; OpenAI notes that conversation items are not subject to the 30-day TTL. It is still provider-specific, so the same portability caveat applies.
Codex and Other Agent Clients
Coding agents hit this when they assume server-side state. The history of OpenAI's Codex is a useful reference:
- The original Codex CLI added a
disable_response_storageoption for ZDR organizations, so the client stored response items itself. - In September 2025, Codex PR #3212 ("Never store requests") removed that option, and later changes set
store: falseon every Responses request. Current Codex keeps the history locally and replays it with encrypted reasoning, so it does not depend onprevious_response_idover HTTP. Older guides and configs that still includedisable_response_storage = truecome from that earlier period; current releases no longer read the option. - Codex's source does use
previous_response_idon its Responses WebSocket transport. For custom providers, thesupports_websocketssetting defaults tofalse; leave it off unless the provider explicitly supports Responses WebSocket mode.
The byesu Codex CLI guide shows a working provider config for https://byesu.com/v1.
If You're Calling GPT Through byesu
byesu is an AI API gateway with an OpenAI-compatible endpoint at https://byesu.com/v1, supporting both Chat Completions and Responses, billed pay-as-you-go with no subscription.
- Prefer stateless requests. Send the full input with
store: falseas in Fix 1; it behaves the same on every OpenAI-compatible endpoint and removes this error class entirely. - Never reuse IDs across endpoints. A
resp_…ID created on another provider won't resolve here, and the reverse is also true — keep your own history for anything that might switch endpoints.
To get set up, follow the Quick Start.
FAQ
What does previous_response_not_found mean?
It is a 400 invalid_request_error with param previous_response_id. The Responses API could not resolve the ID you passed from the state available to it, so it cannot continue that chain. Nothing is generated; retrying with the same ID fails the same way.
Why is my response ID not found right after I created it?
Most often the original request ran with store set to false, so the response was never saved. Organizations under Zero Data Retention are treated as store: false even if you send true. The other common cause is sending the ID to a different provider or endpoint than the one that created it.
How long are Responses API responses stored?
OpenAI stores Response objects for 30 days by default when store is true, which is the default when omitted. After that the ID can no longer be used with previous_response_id. Items added to a Conversation object are not subject to the 30-day TTL.
How do I continue a conversation without previous_response_id?
Keep the conversation yourself: append each response's output items to your own input list and send the full list on every request with store set to false. Reasoning items then carry encrypted_content so reasoning state continues across turns without anything stored server-side.
Does Codex still need disable_response_storage?
The option was removed from the Codex codebase in September 2025 (openai/codex PR #3212), and current Codex sends store: false on every Responses request. Codex keeps the history locally and resends it, so it does not depend on previous_response_id over HTTP.
