Skip to content

Commit 2fcb1fc

Browse files
author
Hex
committed
fix: retry history fetch on failure + fix chunked encoding
Root cause: 1.2MB history responses sometimes failed with ERR_CONTENT_LENGTH_MISMATCH or ERR_INCOMPLETE_CHUNKED_ENCODING, leaving the chat empty ('Start a conversation' shown). Fixes: - Client retries history fetch up to 3x with backoff on failure - Server uses res.send() instead of res.json() for large history payloads to avoid Content-Length calculation issues - Only sets turns when response has actual data (prevents clearing existing turns on retry failure)
1 parent ff73877 commit 2fcb1fc

File tree

2 files changed

+25
-9
lines changed

2 files changed

+25
-9
lines changed

packages/client/src/features/chat/store.ts

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -219,13 +219,24 @@ function connectSSE(threadKey: string): void {
219219
if (!threadKey) return
220220

221221
// Fetch history via HTTP GET immediately (fast, parallel with SSE)
222-
fetch(`/api/threads/${encodeURIComponent(threadKey)}/history`)
223-
.then((r) => r.json())
224-
.then((data) => {
225-
setTurns(data.turns ?? [])
226-
setHasOlderMessages(data.hasMore ?? false)
227-
})
228-
.catch(() => {})
222+
const fetchHistory = (attempt = 0) => {
223+
fetch(`/api/threads/${encodeURIComponent(threadKey)}/history`)
224+
.then((r) => {
225+
if (!r.ok) throw new Error(`HTTP ${r.status}`)
226+
return r.json()
227+
})
228+
.then((data) => {
229+
if (data.turns?.length) {
230+
setTurns(data.turns)
231+
setHasOlderMessages(data.hasMore ?? false)
232+
}
233+
})
234+
.catch(() => {
235+
// Retry up to 3 times with backoff (handles ERR_CONTENT_LENGTH_MISMATCH)
236+
if (attempt < 3) setTimeout(() => fetchHistory(attempt + 1), 1000 * (attempt + 1))
237+
})
238+
}
239+
fetchHistory()
229240

230241
const url = `/api/threads/${encodeURIComponent(threadKey)}/events`
231242
eventSource = new EventSource(url)

packages/server/src/chat/routes.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,14 +101,19 @@ export function createChatRoutes(chatModule: ChatModule, backend: AgentBackend,
101101
// Check response cache first
102102
const cached = historyResponseCache.get(threadKey)
103103
if (cached && Date.now() - cached.timestamp < HISTORY_CACHE_TTL) {
104-
return res.json(cached.data)
104+
const json = JSON.stringify(cached.data)
105+
res.setHeader('Content-Type', 'application/json')
106+
return res.send(json)
105107
}
106108

107109
try {
108110
const result = await backend.getHistory(sessionKey)
109111
const data = { turns: result.turns, hasMore: result.hasMore }
110112
historyResponseCache.set(threadKey, { data, timestamp: Date.now() })
111-
res.json(data)
113+
// Use res.send to avoid Content-Length mismatch with large payloads
114+
const json = JSON.stringify(data)
115+
res.setHeader('Content-Type', 'application/json')
116+
res.send(json)
112117
res.json({ turns: result.turns, hasMore: result.hasMore })
113118
} catch {
114119
res.json({ turns: [], hasMore: false })

0 commit comments

Comments
 (0)