Description
Every assistant reply in the Control UI webchat (port 18789) appears twice in the chat view. This happens consistently on every message, not intermittently.
Environment
- OpenClaw version: 2026.1.30
- Browser: Chromium-based (tested on multiple)
- OS: Debian Linux (x64)
- Gateway mode: local, LAN bind
Steps to reproduce
- Open the Control UI webchat at
http://<gateway-ip>:18789/chat
- Send any message
- Observe the assistant reply appears twice
Analysis
I traced through the minified client JS (index-CXUONUC9.js) and the server-side server-chat.js. The server transcript (.jsonl) contains no duplicates — each assistant message appears exactly once. This is purely a client-side rendering issue.
Likely cause
When a chat event with state: 'final' arrives:
chatStream is set to null (clearing the streaming entry)
St(e) (chat.history fetch) is called asynchronously
- The history response replaces
chatMessages entirely
The duplicate likely occurs because:
- The final chat event's
message payload may be rendered as a new entry before chatStream is fully cleared in the same render cycle
- OR
chat.history is being triggered from multiple paths (e.g., both the final event handler AND a tab re-focus / reconnect handler)
Key code paths (from minified source)
zl() — handles chat event state transitions (delta/final/error)
St() — fetches chat.history and replaces chatMessages
vg() — gateway event dispatcher, calls St(e) on state === 'final'
ei() — tab init, also calls Zo() → St() for chat tab
Expected behavior
Each assistant message should appear exactly once.
Workaround
Refreshing the page shows correct history (no duplicates), confirming it's a live rendering issue only.
Description
Every assistant reply in the Control UI webchat (port 18789) appears twice in the chat view. This happens consistently on every message, not intermittently.
Environment
Steps to reproduce
http://<gateway-ip>:18789/chatAnalysis
I traced through the minified client JS (
index-CXUONUC9.js) and the server-sideserver-chat.js. The server transcript (.jsonl) contains no duplicates — each assistant message appears exactly once. This is purely a client-side rendering issue.Likely cause
When a
chatevent withstate: 'final'arrives:chatStreamis set tonull(clearing the streaming entry)St(e)(chat.history fetch) is called asynchronouslychatMessagesentirelyThe duplicate likely occurs because:
messagepayload may be rendered as a new entry beforechatStreamis fully cleared in the same render cyclechat.historyis being triggered from multiple paths (e.g., both thefinalevent handler AND a tab re-focus / reconnect handler)Key code paths (from minified source)
zl()— handles chat event state transitions (delta/final/error)St()— fetcheschat.historyand replaceschatMessagesvg()— gateway event dispatcher, callsSt(e)onstate === 'final'ei()— tab init, also callsZo()→St()for chat tabExpected behavior
Each assistant message should appear exactly once.
Workaround
Refreshing the page shows correct history (no duplicates), confirming it's a live rendering issue only.