Bug Report: WebChat Messages Disappear After Brief Display
Date: 2026-05-04
Reporter: Tim O'Brien (via SmartAlec)
Severity: High — breaks usability of primary control surface
Component: WebChat UI / Control Dashboard
OpenClaw Version: 2026.5.2 (8b2a6e5)
Summary
Agent (assistant) messages render in the WebChat control UI for approximately 1–2 seconds, then vanish from the chat stream. The same messages remain fully visible and persistent in the TUI (openclaw tui). User messages are unaffected.
Environment
| Item |
Value |
| Gateway host |
Srv1-AI1 (192.168.50.58:18789) |
| Access method |
WebChat via browser control UI |
| Model |
ollama/kimi-k2.6:cloud |
| Gateway runtime |
native (PID 3778, stable 12h+) |
Root Cause (Confirmed from Source)
This is a known class of bug in the WebChat UI, caused by three interrelated design issues in ui/src/ui/controllers/chat.ts and ui/src/ui/app-gateway.ts:
1. History Full-Replace Race Condition (Primary Cause)
When a run completes with tool events, handleTerminalChatEvent fires loadChatHistory() which does a full replace of chatMessages:
// app-gateway.ts:343
if (hadToolEvents && state === "final") {
void loadChatHistory(host); // async, fire-and-forget
return true;
}
// controllers/chat.ts
state.chatMessages = messages.filter(m => !isAssistantSilentReply(m));
This is async and void-cast. If the gateway hasn't persisted the final transcript to the session store when chat.history responds, the final message is missing from the response. The streaming text was visible, then gets wiped by the incomplete history.
This is the root cause of #11139, #37083, and #66316 RC#1.
2. Run State Is Tab-Local, Not Session-Scoped
chatRunId is only set by the tab that called sendChatMessage(). Passive tabs (or tabs that reconnected) keep chatRunId = null, which causes isChatBusy() false-positives and causes handleChatEvent to drop non-final events from runs where payload.runId !== chatRunId.
Relevant code:
// chat.ts:314
if (payload.runId && state.chatRunId && payload.runId !== state.chatRunId) {
// only "final" state handled — everything else returns null (dropped)
return null;
}
3. Streaming Segment Deduplication Issues
When a tool call interrupts the stream, the client saves the current chatStream as a segment. Subsequent deltas (still containing the full accumulated text) then show overlapping content. The loadChatHistory() call that previously masked this was removed in commit 0e8672a to fix a reload storm, exposing the segment deduplication bug.
Related: #47399 (deduplicate streaming chat segments)
Why TUI Keeps Messages But WebChat Loses Them
- TUI reads from local session state (in-memory transcript), survives reconnects
- WebChat reads from gateway API (
sessions/history) which may lag behind real-time push events
- WebChat does full replacement of its message array on every history load; TUI appends incrementally
Related Issues
| Issue |
Title |
Status |
| #37083 |
Messages disappear during tool execution |
Open |
| #11139 |
Messages disappear when assistant sends text + toolCall |
Open |
| #29472 |
Streamed message collapses to show only content after last tool call |
Open |
| #39686 |
Duplicate messages after WebSocket reconnect |
Closed (fixed dedup) |
| #66316 RC#1 |
History reload race: final message vanishes |
Open |
| #66332 |
Session-scoped run tracking, incremental history merge |
Proposed fix |
| #47399 |
Deduplicate streaming chat segments |
Merged |
Verified Fix (from Source Analysis)
The maintainers have already identified the fix in issue #66332. Three changes needed:
- Adopt
runId session-wide — passive tabs should adopt the runId from delta events
- Incremental history merge — replace the full-swap with a merge that preserves existing messages
- Concatenate stream segments before markdown rendering — or auto-close unclosed code fences
Files to change: ui/src/ui/controllers/chat.ts, ui/src/ui/app-chat.ts, ui/src/ui/app-gateway.ts, ui/src/ui/app-tool-stream.ts, ui/src/ui/views/chat.ts
Workarounds (Until Fix Lands)
- Use TUI (
openclaw tui) for critical sessions — messages are persistent there
- Keep TUI open alongside WebChat to catch disappearing messages
- Request concise single-block replies in WebChat; avoid long multi-part responses with tool calls
- Wait 2-3 seconds after the message flashes before interacting — the history reload may complete and restore it
Priority
P1 (High) — The WebChat control UI is the primary user-facing surface. A message-disappearing bug makes it unreliable for production use. Users cannot trust that they have seen all agent output.
Recommended action: This should be filed as a reference to the existing #66332 / #66316 cluster, with Tim's environment details (kimi-k2.6, native gateway, tool-heavy sessions) added as additional reproduction data.
Filed by SmartAlec on behalf of Tim O'Brien.
Bug Report: WebChat Messages Disappear After Brief Display
Date: 2026-05-04
Reporter: Tim O'Brien (via SmartAlec)
Severity: High — breaks usability of primary control surface
Component: WebChat UI / Control Dashboard
OpenClaw Version: 2026.5.2 (8b2a6e5)
Summary
Agent (assistant) messages render in the WebChat control UI for approximately 1–2 seconds, then vanish from the chat stream. The same messages remain fully visible and persistent in the TUI (
openclaw tui). User messages are unaffected.Environment
Root Cause (Confirmed from Source)
This is a known class of bug in the WebChat UI, caused by three interrelated design issues in
ui/src/ui/controllers/chat.tsandui/src/ui/app-gateway.ts:1. History Full-Replace Race Condition (Primary Cause)
When a run completes with tool events,
handleTerminalChatEventfiresloadChatHistory()which does a full replace ofchatMessages:This is
asyncandvoid-cast. If the gateway hasn't persisted the final transcript to the session store whenchat.historyresponds, the final message is missing from the response. The streaming text was visible, then gets wiped by the incomplete history.This is the root cause of #11139, #37083, and #66316 RC#1.
2. Run State Is Tab-Local, Not Session-Scoped
chatRunIdis only set by the tab that calledsendChatMessage(). Passive tabs (or tabs that reconnected) keepchatRunId = null, which causesisChatBusy()false-positives and causeshandleChatEventto drop non-final events from runs wherepayload.runId !== chatRunId.Relevant code:
3. Streaming Segment Deduplication Issues
When a tool call interrupts the stream, the client saves the current
chatStreamas a segment. Subsequent deltas (still containing the full accumulated text) then show overlapping content. TheloadChatHistory()call that previously masked this was removed in commit0e8672ato fix a reload storm, exposing the segment deduplication bug.Related: #47399 (deduplicate streaming chat segments)
Why TUI Keeps Messages But WebChat Loses Them
sessions/history) which may lag behind real-time push eventsRelated Issues
Verified Fix (from Source Analysis)
The maintainers have already identified the fix in issue #66332. Three changes needed:
runIdsession-wide — passive tabs should adopt the runId from delta eventsFiles to change:
ui/src/ui/controllers/chat.ts,ui/src/ui/app-chat.ts,ui/src/ui/app-gateway.ts,ui/src/ui/app-tool-stream.ts,ui/src/ui/views/chat.tsWorkarounds (Until Fix Lands)
openclaw tui) for critical sessions — messages are persistent therePriority
P1 (High) — The WebChat control UI is the primary user-facing surface. A message-disappearing bug makes it unreliable for production use. Users cannot trust that they have seen all agent output.
Recommended action: This should be filed as a reference to the existing #66332 / #66316 cluster, with Tim's environment details (kimi-k2.6, native gateway, tool-heavy sessions) added as additional reproduction data.
Filed by SmartAlec on behalf of Tim O'Brien.