cloudflare / cloudflare/agents
useAgentChat still hits React #185 with a 50ms throttle on agents@0.22.0
- Dominant language
- TypeScript
- Stars
- 5.6k
- Forks
- 711
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 53
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.0`
- `ai@7.0.93`
- `@ai-sdk/react@4.0.96`
- `react@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:
```ts
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
- #1361
- #1732
- #1913
- #2058
- #2217
Contributor guide
Assessment
This issue has not been assessed yet.