openclaw / openclaw/openclaw-windows-node

[Bug] 2026.9.3: tray connects as node but no window ever opens — UI thread spins in InitialTailPositioner LayoutUpdated to StartBringItemIntoView loop

Open
#1,409 1 comment 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

clawsweeper:needs-info clawsweeper:needs-maintainer-review clawsweeper:no-new-fix-pr impact:crash-loop impact:ux-release-blocker issue-rating: 🦐 gold shrimp P0
Dominant language
C#
Stars
2.1k
Forks
295
Avg merge
1d 6h
Merged PRs (30d)
99

Description

Summary

On 2026.9.3, OpenClaw.Tray.WinUI starts, shows its tray icon, and connects to the gateway as a node normally — but no window is ever created and clicking the tray does nothing. The UI thread pegs one core permanently inside an initial scroll-to-tail positioning loop in the chat list, and because that runs inside Application.Start, window creation never completes.

This does not reproduce on 2026.7.1.0, where the same machine's UI thread loop had a different signature (see "Regression range" below).

Environment

  • OpenClaw Companion: 2026.9.3.0 (ProductVersion 2026.9.3+84928c4370bc52d7f19127c65a637c7a28aab46e), Unpackaged install under %LOCALAPPDATA%\OpenClawTray\
  • OpenClaw Gateway: 2026.9.3, protocol 4, loopback bind reached over an SSH tunnel
  • OS: Windows 11 Pro 10.0.26200, x64
  • Node mode enabled; gateway handshake succeeds (hello-ok, Node status: Connected)

Symptoms

  1. Tray icon appears and reports connected.
  2. No main window is ever shown. Process.MainWindowHandle == 0.
  3. Clicking the tray icon does nothing.
  4. OpenClaw.Tray.WinUI burns ~100% of one core indefinitely (439.6 s CPU across ~8 minutes of uptime).
  5. Win32_PerfFormattedData_PerfProc_Thread shows thread 0 at 97–99%, ThreadState 2 (Running).
  6. Background work is unaffected — the node stays connected and the log keeps advancing.

Evidence

Four dotnet-stack report samples of the live process (three consecutive, plus one more after a deliberate revert-and-reproduce) all land on the same UI-thread stack:

Thread (0x5818):
  [Native Frames]
  Microsoft.WinUI!ABI.Microsoft.UI.Xaml.Controls.IItemsViewMethods.StartBringItemIntoView(class WinRT.IObjectReference,int32,class Microsoft.UI.Xaml.BringIntoViewOptions)
  Microsoft.WinUI!Microsoft.UI.Xaml.Controls.ItemsView.StartBringItemIntoView(int32,class Microsoft.UI.Xaml.BringIntoViewOptions)
  OpenClaw.Tray.WinUI!OpenClawTray.Chat.<ReactorItemsViewScrollController>...__InitialTailPositioner.StartTailRequest(value class OpenClawTray.Chat.TailNavigationRequest)
  OpenClaw.Tray.WinUI!OpenClawTray.Chat.<ReactorItemsViewScrollController>...__InitialTailPositioner+<>c__DisplayClass20_0.<OnLayoutUpdated>b__0()
  Microsoft.InteractiveExperiences.Projection!ABI.Microsoft.UI.Dispatching.DispatcherQueueHandler.Do_Abi_Invoke(int)
  Microsoft.WinUI!ABI.Microsoft.UI.Xaml.IApplicationStaticsMethods.Start(class WinRT.IObjectReference,class Microsoft.UI.Xaml.ApplicationInitializationCallback)
  Microsoft.WinUI!Microsoft.UI.Xaml.Application.Start(class Microsoft.UI.Xaml.ApplicationInitializationCallback)
  OpenClaw.Tray.WinUI!OpenClawTray.Program.Main(class System.String[])

A second thread sits in GC.RunFinalizersWinRT.IObjectReference.Finalize(), consistent with WinRT wrappers being allocated and discarded at rate inside the loop.

Reading: InitialTailPositioner handles LayoutUpdated and calls ItemsView.StartBringItemIntoView to position the chat at the newest message. That bring-into-view invalidates layout, which re-fires LayoutUpdated, which requests it again. The cycle never converges. Because it runs on the dispatcher inside Application.Start, the window never finishes being created.

Diagnostic trap worth noting

Process.Responding reports True throughout, which makes the app look healthy to any monitoring that checks it. .NET evaluates Responding against the main window, and with MainWindowHandle == 0 there is no window to test, so it answers vacuously. Anyone triaging this should check MainWindowHandle alongside Responding.

Relatedly, each tray click spawns a second process that logs Previous session did not exit cleanly and exits — it is trying to hand off to the pegged instance and failing. The log fills with what look like repeated crashes but are actually failed activations.

Reproduction / confirmation

  1. Launch 2026.9.3 with node mode enabled and an existing agent session.
  2. Observe the tray connects but no window appears; sample the process CPU and per-thread load.
  3. Set "UseLegacyWebChat": true in %APPDATA%\OpenClawTray\settings.json and restart → window appears, CPU drops to 3–6%.
  4. Set it back to false and restart → the failure reproduces immediately and identically, and a fresh stack sample lands on the same frames.

Step 4 was run deliberately to confirm the workaround is load-bearing rather than coincidental.

What does NOT help

  • "ShowChatToolCalls": false — mitigated the previous 2026.7.x UI-thread loop on this machine; has no effect on this one.
  • Deleting last-chat-state.json to prevent thread restore — still 100% CPU, still MainWindowHandle == 0. The positioner runs regardless of restored state, so this is not per-session-state dependent.
  • Resetting the agent session — the loop is in initial positioning, not in transcript volume.

Workaround

"UseLegacyWebChat": true in %APPDATA%\OpenClawTray\settings.json. This routes chat through the WebView surface and takes the native ItemsView chat out of service. Window creation then completes and the app is usable.

Regression range and probable culprit

ReactorItemsViewScrollController appears nowhere in this machine's 2026.7.1.0 stack captures (that build's loop was in ReactorHostControl.RenderLoopReactorChatComposer / ToolCallCardRendererLocalizationHelper.GetString). So this looks introduced in 2026.9.3.

The same class and LayoutUpdated handling were reworked immediately before this release:

  • #1286 — "async content load pins scroll at old position" (names Chat/ReactorItemsViewScrollController.cs, InitialTailPositioner, LayoutUpdated)
  • #1285 — "chat auto-scrolls back to an old position after each assistant reply"
  • #1148 — "chat does not auto-scroll to most recent message" (still open)

Those changes were fixing "scroll settles in the wrong place"; this looks like the resulting "scroll never settles". A convergence guard on the tail request (bail once the target is satisfied, or cap re-entrant requests per layout pass) would likely close it.


Full dotnet-stack captures (three concurring samples plus the post-revert confirmation) are available on request — happy to paste them or attach if useful.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with Chat/ReactorItemsViewScrollController.cs, focusing on InitialTailPositioner, its LayoutUpdated handler, and calls to ItemsView.StartBringItemIntoView. Reproduce with UseLegacyWebChat set to false and confirm the window never appears and the UI thread spins. Done means native chat reaches a stable tail position, window creation completes, and CPU usage no longer remains pegged.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
desktop
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.