Repository navigation
useAgentChat still hits React #185 with a 50ms throttle on agents@0.22.0 #2267
Description
Summary
useAgentChat can still enter status: "error" with React #185 (Maximum update depth exceeded) during a long streamed turn, even when chat updates are explicitly throttled at 50 ms.
This looks related to #1361 / #1732, but the occurrence described below is on agents@0.22.0, after the default-throttle work in #2058, with experimental_throttle: 50 explicitly configured. The application also carries an equivalent of the proposed #2217 fix, so the clientToolResults no-op cleanup dispatch should not be the remaining source.
Environment
agents@0.22.0ai@7.0.93@ai-sdk/react@4.0.96react@19.2.7- Mobile Safari
- Production build
useAgentChat({ resume: true, experimental_throttle: 50 })
Actual behavior
During a long streamed chat turn, the client intermittently throws React #185. The source-mapped stack reaches the Agents chat response handling / setMessages path, then the AI SDK ReactChatState subscriber callback and React's forceStoreRerender. The client stream is assigned an error even though this is a React-side update-depth failure.
Why this appears distinct from #2217
The affected application has a pre-dispatch stale-entry check equivalent to the fix proposed in #2217. The clientToolResults cleanup effect does not call setClientToolResults unless a stale entry actually exists, so it no longer schedules a no-op update on every streamed chatMessages change.
Suspected remaining update source
The fallback/observer branch still applies each live broadcast update directly to the AI SDK store:
const result = broadcastTransition(streamStateRef.current, {
type: "response",
streamId: data.id,
// ...
});
streamStateRef.current = result.state;
if (result.messagesUpdate) {
setMessages(result.messagesUpdate);
}Current main still has this write:
https://github.com/cloudflare/agents/blob/main/packages/agents/src/chat/react.tsx#L2157-L2163
For a live observed stream, broadcastTransition can produce a messagesUpdate for every chunk. The configured useChat throttle limits React publication frequency, but it does not prevent these per-chunk setMessages calls from entering the store. This is a candidate rather than a proven root cause.
One possible mitigation would be to coalesce the latest accumulated observer update before calling setMessages, with an immediate flush for done / replayComplete and cancellation on clear/unmount.
Reproduction status
We do not yet have a deterministic standalone reproduction. Stress attempts in Chromium with a mobile viewport did not reproduce it; the failure has only been observed intermittently in Mobile Safari so far. We can provide a sanitized source-mapped stack if useful.
Expected behavior
Long and/or observed streamed turns should complete without exhausting React's nested-update budget or moving useAgentChat to status: "error".
Related
- useAgentChat can throw "Maximum update depth exceeded" during dense streamed tool-input-delta bursts #1361
- useAgentChat: React #185 "Maximum update depth exceeded" on fast streamed chunk bursts — per-frame setMessages + synchronous ReactChatState subscriber fan-out (still reproduces on 0.8.1; re: #1361) #1732
- useAgentChat: "Maximum update depth exceeded" thrown during stream resume after a reconnect — surfaces as a terminal error mid-turn (not fixed by #1838) #1913
- feat(chat): throttle chat UI updates by default #2058
- useAgentChat: the clientToolResults cleanup effect dispatches setState once per streamed chunk, accumulating nestedUpdateCount to the React #185 throw #2217
Activity