Windows: statusline cancellation (taskkill /T) and cross-session liveness probes overload WMI - WmiPrvSE pinned at 300-550% CPU with ~10 concurrent sessions

Open 💬 0 comments Opened Jul 3, 2026 by heinonmatti

Environment

  • Claude Code v2.1.199, native Windows build (claude.exe)
  • Windows 11 Education 10.0.22631, AMD Ryzen 5 7535U (6c/12t), 32 GB RAM
  • Git for Windows installed, so statusline commands run through the documented Git-Bash wrapper
  • ~9-12 concurrent interactive sessions across several projects
  • Custom statusline in settings.json: "statusLine": { "type": "command", "command": "powershell.exe -NoProfile -ExecutionPolicy Bypass -File .../statusline-command.ps1", "refreshInterval": 3 } - the script takes ~480 ms end to end (PowerShell cold start dominates)
  • Possibly relevant config: CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 and "remoteControlAtStartup": true were enabled; unclear which subsystem owns the liveness probing described below

Summary

Two undocumented Windows behaviours - (1) statusline cancellation killing process trees via taskkill /T, and (2) cross-session liveness probes implemented as spawned PowerShell + WMI one-liners - combine into a feedback loop that pinned the shared WMI Provider Host (WmiPrvSE.exe hosting CIMWin32) at 300-550% CPU for a full day (~124,000 CPU-seconds accumulated over 21 h), flooded the WMI-Activity log with errors, made other WMI clients on the machine time out, and left every session's statusline permanently blank.

Defect 1: statusline cancellation = taskkill /T = full WMI process-table scan per cancel

The statusline docs say in-flight executions are cancelled when a new update fires (300 ms debounce), but not how. Observed on Windows: cancellation runs taskkill /PID <pid> /T /F against the render's process tree. taskkill /T builds the tree by querying WMI - a 12 s ETW trace of Microsoft-Windows-WMI-Activity captured 40 of these full enumerations in 12 seconds:

Provider::ExecQuery - CIMWin32 : select __RELPATH, __PATH, ProcessId, CSName, Caption, SessionId,
ThreadCount, WorkingSetSize, KernelModeTime, UserModeTime, ParentProcessId from Win32_Process

One full Win32_Process enumeration costs ~533 ms of provider CPU on this machine (measured with Measure-Command { Get-CimInstance Win32_Process }).

With N concurrent sessions and a statusline slower than the 300 ms debounce, cancellations fire several times per second, so the WMI provider does 1.5-2+ core-seconds of scan work per wall-clock second, which slows the next renders, which causes more cancellations. Observed effects:

  • WmiPrvSE.exe (shared CIMWin32 host) pinned at 300-550% CPU; killing it is whack-a-mole - a fresh host re-wedges within seconds because the sources immediately reconnect
  • WMI-Activity/Operational floods with event 5858 / 0x800706BA "Could not send status to client" (~470/hour) - the killed render/probe clients vanish mid-operation
  • All statuslines permanently blank (renders killed before they print; docs: no output = blank line)
  • Every render also spawns a bash.exe chain (Git\bin\bash.exe re-execs usr\bin\bash.exe) + conhost.exe + powershell.exe: 543 process creations measured in 10 seconds across ~9 idle-ish sessions

Defect 2: cross-session liveness probes via spawned PowerShell + WMI

claude.exe checks whether other Claude Code processes are alive by spawning (command template found embedded in the claude.exe binary):

powershell.exe -NoProfile -Command "(Get-CimInstance Win32_Process -Filter \"ProcessId=<pid>\").CreationDate.Ticks"

Observed:

  • periodic sweeps probing each registered session PID (one spawned PowerShell per peer)
  • a failure mode where one session probed a single peer PID 2-3 times per second for hours; after that peer process was killed, the sweeps re-aimed at the remaining sessions
  • when WMI is overloaded, probes time out or hang - one probe process hung for 4.5 h and survived repeated kill attempts; every timeout logs another 5858 error
  • undocumented; no setting or env var found to tune or disable it

Each probe is a full PowerShell cold start (~450 ms CPU) plus a WMI round-trip, for a value (process creation time) obtainable in microseconds via GetProcessTimes / NtQueryInformationProcess, or Node's own process APIs.

Reproduction

  1. Windows 11 with Git for Windows installed; set a custom statusline command that takes >300 ms (any powershell.exe -File ... script qualifies - cold start alone is ~400 ms) with "refreshInterval": 3
  2. Open ~8-10 interactive sessions and let them sit
  3. Watch WmiPrvSE.exe CPU climb in Task Manager; watch Microsoft-Windows-WMI-Activity/Operational fill with 5858 / 0x800706BA; statuslines go blank
  4. logman create trace wmiact -p Microsoft-Windows-WMI-Activity 0xffffffffffffffff 0xff -o wmiact.etl -ets, wait ~12 s, logman stop wmiact -ets, decode with tracerpt - the trace shows the taskkill-signature full Win32_Process enumerations and the per-peer probe queries

Expected behaviour

  • Read process start/liveness via native APIs instead of spawning powershell.exe + WMI per check
  • Cancel statusline renders without taskkill /T's WMI tree walk (native process enumeration such as CreateToolhelp32Snapshot, or spawn renders into a Job Object so the tree can be killed directly)
  • Ideally: let statusLine accept a "shell" field like hooks do, so the Git-Bash wrapper (two extra bash processes + conhost per render) can be avoided on machines where MSYS2 bash is unreliable

Workaround that resolved it here

  • Ported the statusline script to Node (80 ms vs 481 ms, output identical) so renders finish inside the 300 ms debounce window - cancellations and their taskkill WMI scans stopped
  • Raised refreshInterval from 3 to 10
  • WMI provider CPU dropped from ~550% sustained to idle; statuslines render again

View original on GitHub ↗