Skip to content

fix: Prevent duplicate chat message rendering caused by React StrictM…#5951

Open
yuyol wants to merge 3 commits intoFlowiseAI:mainfrom
yuyol:fix/agent-chat-duplicate-render
Open

fix: Prevent duplicate chat message rendering caused by React StrictM…#5951
yuyol wants to merge 3 commits intoFlowiseAI:mainfrom
yuyol:fix/agent-chat-duplicate-render

Conversation

@yuyol
Copy link

@yuyol yuyol commented Mar 11, 2026

Problem

In the ChatMessage component, the getChatmessageApi (and getAllExecutionsApi) was being called twice on mount. While the API was always invoked twice, the chat messages were sometimes rendered in duplicate — appearing as two copies of the entire conversation history.

182930d1874714ea4da91681d03cdbb

Root Cause (Observed behavior)

The application uses React.StrictMode (packages/ui/src/index.jsx), which in React 18 development mode intentionally double-invokes useEffect callbacks (mount → cleanup → re-mount) to help surface impure side effects.

This caused the initialization useEffect (dependent on [open, chatflowid]) to call getChatmessageApi.request(chatflowid) twice, resulting in two network requests.

The data-handling useEffect (dependent on [getChatmessageApi.data]) used a simple append pattern:

setMessages((prevMessages) => [...prevMessages, ...loadedMessages])

When both API responses arrived after the StrictMode cleanup had already reset the messages state, loadedMessages was appended twice, causing duplicate rendering. When timing was different (first response arrived before cleanup), only one copy survived — explaining the intermittent nature of the bug.

Fix

Changed the setMessages calls in both the getChatmessageApi.data and getAllExecutionsApi.data useEffect handlers from a simple append to a deduplicated append:

setMessages((prevMessages) => {
    const initialMessages = prevMessages.filter(
        (msg) => !msg.id || !loadedMessages.some((lm) => lm.id === msg.id)
    )
    return [...initialMessages, ...loadedMessages]
})

This makes the operation idempotent — no matter how many times the API data triggers the effect, messages with the same id will not be duplicated. Messages without an id (e.g., the initial welcome message, in-progress user messages) are always preserved.

Changes

  • packages/ui/src/views/chatmessage/ChatMessage.jsx
    • getChatmessageApi.data useEffect: replaced [...prevMessages, ...loadedMessages] with deduplicated merge by id
    • getAllExecutionsApi.data useEffect: same deduplication fix

Impact

  • No behavioral change in production — StrictMode double-invocation only occurs in development mode, but the fix is safe and correct for all environments
  • No API call reduction — the two calls are a StrictMode artifact; the fix ensures the UI handles them gracefully
  • Backward compatible — messages without id (welcome message, streaming messages in progress) are unaffected by the filter logic

How to test

  1. Run Flowise in development mode
  2. Open a chatflow with existing chat history
  3. Observe the network tab — getChatmessageApi may be requested twice
  4. Verify that chat history is rendered only once and no duplicate messages appear

@yuyol
Copy link
Author

yuyol commented Mar 11, 2026

/gemini review

@gemini-code-assist
Copy link
Contributor

Warning

Gemini encountered an error creating the summary. You can try again by commenting /gemini summary.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

The pull request addresses a bug where duplicate chat messages were rendered due to React StrictMode's double invocation of useEffect in development. The fix involves deduplicating messages based on their IDs before appending them to the message list. This review focuses on the correctness and maintainability of the implemented solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant