router-for-me/CLIProxyAPI · error
previous_response_not_found
previous_response_not_found
Error message
{"error":{"message":"Previous response is not available on this websocket; resend the full conversation input without previous_response_id","type":"invalid_request_error","code":"previous_response_not_found","param":"previous_response_id"}} What it means
Returned when a client sends a `response.create` websocket frame carrying a `previous_response_id` while the proxy has no stored turn state for that websocket session (`len(lastRequest) == 0` at sdk/api/handlers/openai/openai_responses_websocket.go:488). The proxy only supports incremental input when it has replayed/recorded the prior turn itself; a bare previous_response_id from a different or already-forgotten session cannot be resolved. It replies HTTP 409-style ErrorMessage with code `previous_response_not_found` instead of forwarding an invalid continuation upstream.
Source
Thrown at sdk/api/handlers/openai/openai_responses_websocket.go:700
func websocketUpgradeHeaders(req *http.Request) http.Header {
headers := http.Header{}
if req == nil {
return headers
}
// Keep the same sticky turn-state across reconnects when provided by the client.
turnState := strings.TrimSpace(req.Header.Get(wsTurnStateHeader))
if turnState != "" {
headers.Set(wsTurnStateHeader, turnState)
}
return headers
}
func responsesWebsocketPreviousResponseNotFoundError() *interfaces.ErrorMessage {
return &interfaces.ErrorMessage{
StatusCode: http.StatusConflict,
Error: errors.New(
`{"error":{"message":"Previous response is not available on this websocket; resend the full conversation input without previous_response_id","type":"invalid_request_error","code":"previous_response_not_found","param":"previous_response_id"}}`,
),
}
}
View on GitHub (pinned to 78f0c4079e)
Solutions
- Resend the full conversation input (all messages) with previous_response_id removed on the first request of the websocket session.
- On reconnect, echo back the turn-state header value the server gave you (wsTurnStateHeader) so the sticky turn state is restored.
- Only send previous_response_id on the second and later response.create frames of the same websocket session.
- If you need cross-session continuation, use the HTTP Responses endpoint instead, or enable native websocket passthrough mode.
Example fix
// before (first frame on a new websocket)
ws.Send(`{"type":"response.create","previous_response_id":"resp-old","input":[{"type":"message","role":"user","content":"hi"}]}`)
// after (full input, no previous_response_id)
ws.Send(`{"type":"response.create","input":[{"type":"message","role":"user","content":"hi"}]}`) Defensive patterns
Strategy: validation
Validate before calling
// Go client: before sending response.create on a websocket, check session state
func canUsePreviousResponseID(hasPriorTurn bool, req []byte) bool {
if !hasPriorTurn {
return gjson.GetBytes(req, "previous_response_id").String() == ""
}
return true
}
// hasPriorTurn = at least one successful response.create completed on THIS connection Type guard
func isFirstTurnOnSocket(lastResponseID string) bool { return strings.TrimSpace(lastResponseID) == "" } Try / catch
if respErr != nil && strings.Contains(respErr.Error(), "previous_response_not_found") {
// resend full conversation without previous_response_id
delete(payload, "previous_response_id")
payload["input"] = fullConversationInput
resend(payload)
} Prevention
- Track locally whether the current websocket has completed at least one response.create; only then use previous_response_id.
- Persist and re-send the turn-state header on reconnect to restore sticky state.
- Keep the full conversation history client-side so any socket can be restarted from scratch.
When it happens
Trigger: Sending `{"type":"response.create","previous_response_id":"resp-...","input":[...]}` as the FIRST request on a new websocket connection (no prior response.create on this socket); reconnecting with a stale response id but no `X-Turn-State` (wsTurnStateHeader) header/turn-state token; using previous_response_id when native websocket passthrough is disabled and no lastResponseID exists on the session.
Common situations: Client reconnects after a dropped websocket and reuses the old response id; client mixes the HTTP Responses API pattern (stateless previous_response_id) with the proxy's websocket endpoint; turn-state header was not persisted across reconnects so sticky state was lost; switching between auth accounts pins a different session with no history.
Related errors
- wsrelay: connection closed during response
- wsrelay: stream closed
- parse upstream WebRTC offer for TCP proxy: %w
- read upstream WebRTC offer ICE credentials: %w
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/bcda9755c59687ea.
Report an issue: GitHub.