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

  1. Resend the full conversation input (all messages) with previous_response_id removed on the first request of the websocket session.
  2. On reconnect, echo back the turn-state header value the server gave you (wsTurnStateHeader) so the sticky turn state is restored.
  3. Only send previous_response_id on the second and later response.create frames of the same websocket session.
  4. 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

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


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/bcda9755c59687ea. Report an issue: GitHub.