Skip to content

useAgentChat can throw "Maximum update depth exceeded" during dense streamed tool-input-delta bursts #1361

Description

@advait

Summary

useAgentChat can enter status: "error" with:

Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate.

I have a standalone repro that uses:

  • real AIChatAgent
  • real useAgentChat
  • normal cf_agent_use_chat_response streaming
  • a replay derived from a real production failing stream

Reproduction

Repo:

Run:

pnpm install
pnpm dev

Open:

http://127.0.0.1:43110/

The page auto-sends one message and replays a captured multi-tool stream through a real AIChatAgent + useAgentChat path.

Actual result

The page ends in Status: error and renders:

Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate.

The console stack points into the chat-store update path and includes:

ReactChatState.replaceMessage -> callbacks -> forceStoreRerender

Expected result

The streamed assistant response should complete without entering an error state.

Replay shape

The default replay in the repro repo uses:

  • 6 query_history tool calls
  • 91 tool-input-delta chunks
  • 6 tool-input-start
  • 6 tool-input-available
  • 6 tool-output-available
  • fixed 8x replay speed

Why this appears to happen

useAgentChat() installs WebSocketChatTransport, and that transport currently forwards each parsed chunk immediately with controller.enqueue(chunk):

Downstream, every tool-input-delta chunk reparses partial JSON and immediately writes a new assistant message snapshot:

So the failure looks like:

dense chunk burst -> per-chunk assistant message replacement -> synchronous external-store rerender storm

Why I am filing this here

The failing public API is useAgentChat, and the most obvious mitigation point appears to be Cloudflare's websocket transport boundary before chunks reach useChat().

Possible fix directions

Most promising first fix in cloudflare/agents:

  • coalesce consecutive tool-input-delta chunks before calling controller.enqueue(chunk)

Other possible fixes:

  • buffer parsed chunks and flush them to useChat() once per microtask / frame
  • reduce React-visible publish frequency during dense tool-input-delta bursts
  • preserve full chunk fidelity internally, but avoid turning every delta into its own render boundary

Existing mitigation

useChat() already supports experimental_throttle, and useAgentChat() inherits that option through UseChatParams forwarding:

That looks like a workaround, not the root fix.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions