[BUG] Windows: main window silently becomes always-on-top after stealth auto-update (z-order anchor restored behind the topmost taskbar)

Status Closed — not planned
Maintainer reply None cached
Activity 1 comment · opened Sep 3, 2026 · closed Sep 7, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Title:
Windows: main window silently becomes always-on-top after stealth auto-update (z-order anchor restored behind the topmost taskbar)

---

Summary

After a silent auto-update and relaunch, the Claude desktop main window acquires
WS_EX_TOPMOST and stays pinned above every other window. No user action and no
setting is involved, and nothing is persisted, so it is invisible to the app's own
configuration.

Environment

  • Claude desktop 1.44121.4.0, Windows, MSIX/Store install
  • Windows 10 Pro 22H2 (build 19045), x64

Symptom

Alt-Tab appears broken. Focus does move to the other window, but Claude keeps
painting over it, so nothing seems to happen. Minimizing Claude is the only way to
see anything else. This reads to users as "always on top got switched on somehow" —
but no such toggle was touched, and config.json contains no alwaysOnTop key.

Root cause

[stealth-relaunch] saves a z-order anchor on quit via getWindowAbove(ourHwnd), then
on relaunch restores position with moveWindowBehind(ourHwnd, anchor).

When Claude is the frontmost normal window at quit time, the window directly above it
in Z-order is necessarily the lowest topmost window — frequently Shell_TrayWnd (the
taskbar), which carries WS_EX_TOPMOST (ExStyle 0x00000088).

Windows maintains the invariant that all topmost windows sit above all non-topmost ones.
SetWindowPos(hwnd, <topmost window>, ...) therefore promotes the positioned window into
the topmost band and sets WS_EX_TOPMOST on it. No setAlwaysOnTop() call is involved,
which is why nothing is written to config and why the app has no idea it happened.

Because the anchor is chosen blindly, this should reproduce on most stealth relaunches
where Claude was the frontmost window at quit.

Evidence

From %LOCALAPPDATA%\Claude\logs\main.log (dates stripped):

11:13:50 [info] [stealth-relaunch] Saved z-order anchor: 0x10372 (above our 0x50836)
11:13:54 [info] [stealth-relaunch] Loaded z-order anchor: 0x10372
11:13:55 [info] [stealth-relaunch] Restored z-order: our 0x40862 behind anchor 0x10372
  • 0x10372 was Shell_TrayWnd, confirmed independently via FindWindow("Shell_TrayWnd", NULL).
  • Main window ExStyle after the restore: 0x00080108 — includes WS_EX_TOPMOST (0x8).
  • Expected: 0x00080100.

Minimal reproduction

Standalone — does not require Claude, and demonstrates the OS behavior directly.
Creates a 1x1 normal window, inserts it behind the taskbar exactly as
moveWindowBehind() does, and re-reads the extended style.

Add-Type -AssemblyName System.Windows.Forms, System.Drawing
Add-Type -TypeDefinition @'
using System; using System.Runtime.InteropServices;
public class ZT {
  [DllImport("user32.dll")] public static extern int GetWindowLong(IntPtr h, int i);
  [DllImport("user32.dll")] public static extern bool SetWindowPos(IntPtr h, IntPtr a, int x,int y,int cx,int cy, uint f);
  [DllImport("user32.dll", CharSet=CharSet.Unicode)] public static extern IntPtr FindWindow(string c, string n);
}
'@
$tray = [ZT]::FindWindow("Shell_TrayWnd", $null)
"anchor ExStyle=0x{0:X8}" -f [ZT]::GetWindowLong($tray, -20)

$f = New-Object System.Windows.Forms.Form
$f.FormBorderStyle='None'; $f.ShowInTaskbar=$false
$f.Size = New-Object System.Drawing.Size(1,1)
$f.Show(); [System.Windows.Forms.Application]::DoEvents()

"BEFORE ExStyle=0x{0:X8}" -f [ZT]::GetWindowLong($f.Handle, -20)
[void][ZT]::SetWindowPos($f.Handle, $tray, 0,0,0,0, 0x13)   # NOSIZE|NOMOVE|NOACTIVATE
"AFTER  ExStyle=0x{0:X8}" -f [ZT]::GetWindowLong($f.Handle, -20)
$f.Close()

Observed output:

anchor ExStyle=0x00000088
BEFORE ExStyle=0x00010000
AFTER  ExStyle=0x00010008     <-- WS_EX_TOPMOST (0x8) set by the OS

Suggested fix

Any of, smallest first:

  1. After moveWindowBehind(), re-assert non-topmost:

SetWindowPos(hwnd, HWND_NOTOPMOST, 0,0,0,0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE).

  1. At save time, reject an anchor carrying WS_EX_TOPMOST and walk down the Z-order to

the first non-topmost window instead.

  1. Skip the z-order restore when the saved anchor is topmost or no longer valid.

(1) is the smallest safe change; (2) fixes it at the source.

Workaround

Restart the app, or clear the flag externally with
SetWindowPos(hwnd, HWND_NOTOPMOST, ...) over each claude.exe top-level window.

What Should Happen?

Always on top should not be set by default as it is a distruptive block to user experience. it requires users to minimize claude app to see other apps/windows.

Error Messages/Logs

Steps to Reproduce

Install claude on windows 10 latest version, then launching it. Then launch other apps to open more windows.
trying to alt+tab we see the issue.

Claude Model

None

Is this a regression?

Yes, this worked in a previous version

Last Working Version

_No response_

Claude Code Version

Claude 1.44121.4 (0d57a2) 2026-09-02T23:50:20.000Z

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

PowerShell

Additional Information

_No response_

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗