Skip to content

[Bug] WebChat messages disappear after brief display — history reload race + tool stream collapse #83949

@legupsystems

Description

@legupsystems

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:

  1. Adopt runId session-wide — passive tabs should adopt the runId from delta events
  2. Incremental history merge — replace the full-swap with a merge that preserves existing messages
  3. 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)

  1. Use TUI (openclaw tui) for critical sessions — messages are persistent there
  2. Keep TUI open alongside WebChat to catch disappearing messages
  3. Request concise single-block replies in WebChat; avoid long multi-part responses with tool calls
  4. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High-priority user-facing bug, regression, or broken workflow.clawsweeper:needs-live-reproClawSweeper needs live local, crabbox, or manual validation to confirm this issue.impact:message-lossChannel message delivery can be lost, duplicated, or misrouted.impact:session-stateSession, memory, transcript, context, or agent state can drift or corrupt.issue-rating: 🐚 platinum hermitGood issue quality with a plausible reproduction path needing some confirmation.

    Type

    No type
    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